1= Ruby Security 2 3The Ruby programming language is large and complex and there are many security 4pitfalls often encountered by newcomers and experienced Rubyists alike. 5 6This document aims to discuss many of these pitfalls and provide more secure 7alternatives where applicable. 8 9Please check the full list of publicly known CVEs and how to correctly report a 10security vulnerability, at: http://www.ruby-lang.org/en/security/ 11Japanese version is here: http://www.ruby-lang.org/ja/security/ 12 13Security vulnerabilities should be reported via an email to 14mailto:security@ruby-lang.org ({the PGP public 15key}[http://www.ruby-lang.org/security.asc]), which is a private mailing list. 16Reported problems will be published after fixes. 17 18== <code>$SAFE</code> 19 20Ruby provides a mechanism to restrict what operations can be performed by Ruby 21code in the form of the <code>$SAFE</code> variable. 22 23However, <code>$SAFE</code> does not provide a secure environment for executing 24untrusted code even at its maximum level of +4+. <code>$SAFE</code> is 25inherently flawed as a security mechanism, as it relies on every unsafe 26operation performed by any C method to be guarded by a <code>$SAFE</code> 27check. If this check is ever missed, the entire security of the system is 28compromised. <code>$SAFE</code> also does not offer any protection against 29denial of service attacks. 30 31If you need to execute untrusted code, you should use an operating system level 32sandboxing mechanism. On Linux, ptrace or LXC can be used to sandbox 33potentially malicious code. Other similar mechanisms exist on every major 34operating system. 35 36== +Marshal.load+ 37 38Ruby's +Marshal+ module provides methods for serializing and deserializing Ruby 39object trees to and from a binary data format. 40 41Never use +Marshal.load+ to deserialize untrusted or user supplied data. 42Because +Marshal+ can deserialize to almost any Ruby object and has full 43control over instance variables, it is possible to craft a malicious payload 44that executes code shortly after deserialization. 45 46If you need to deserialize untrusted data, you should use JSON as it is only 47capable of returning 'primitive' types such as strings, arrays, hashes, numbers 48and nil. If you need to deserialize other classes, you should handle this 49manually. Never deserialize to a user specified class. 50 51== YAML 52 53YAML is a popular human readable data serialization format used by many Ruby 54programs for configuration and database persistance of Ruby object trees. 55 56Similar to +Marshal+, it is able to deserialize into arbitrary Ruby classes. 57For example, the following YAML data will create an +ERB+ object when 58deserialized: 59 60 !ruby/object:ERB 61 src: puts `uname` 62 63Because of this, many of the security considerations applying to Marshal are 64also applicable to YAML. Do not use YAML to deserialize untrusted data. 65 66== Symbols 67 68Symbols are often seen as syntax sugar for simple strings, but they play a much 69more crucial role. The MRI Ruby implementation uses Symbols internally for 70method, variable and constant names. The reason for this is that symbols are 71simply integers with names attached to them, so they are faster to look up in 72hashtables. 73 74Once a symbol is created, the memory used by it is never freed. If you convert 75user input to symbols with +to_sym+ or +intern+, it is possible for an attacker 76to mount a denial of service attack against your application by flooding it 77with unique strings. Because each string is kept in memory until the Ruby 78process exits, this will cause memory consumption to grow and grow until Ruby 79runs out of memory and crashes. 80 81Be careful with passing user input to methods such as +send+, 82+instance_variable_get+ or +_set+, +const_get+ or +_set+, etc. as these methods 83will convert string parameters to symbols internally and pose the same DoS 84potential as direct conversion through +to_sym+/+intern+. 85 86The workaround to this is simple - don't convert user input to symbols. You 87should attempt to leave user input in string form instead. 88 89== Regular expressions 90 91Ruby's regular expression syntax has some minor differences when compared to 92other languages. In Ruby, the <code>^</code> and <code>$</code> anchors do not 93refer to the beginning and end of the string, rather the beginning and end of a 94*line*. 95 96This means that if you're using a regular expression like 97<code>/^[a-z]+$/</code> to restrict a string to only letters, an attacker can 98bypass this check by passing a string containing a letter, then a newline, then 99any string of their choosing. 100 101If you want to match the beginning and end of the entire string in Ruby, use 102the anchors +\A+ and +\z+. 103 104== +eval+ 105 106Never pass untrusted or user controlled input to +eval+. 107 108Unless you are implementing a REPL like +irb+ or +pry+, +eval+ is almost 109certainly not what you want. Do not attempt to filter user input before passing 110it to +eval+ - this approach is fraught with danger and will most likely open 111your application up to a serious remote code execution vulnerability. 112 113== +send+ 114 115'Global functions' in Ruby (+puts+, +exit+, etc.) are actually private instance 116methods on +Object+. This means it is possible to invoke these methods with 117+send+, even if the call to +send+ has an explicit receiver. 118 119For example, the following code snippet writes "Hello world" to the terminal: 120 121 1.send(:puts, "Hello world") 122 123You should never call +send+ with user supplied input as the first parameter. 124Doing so can introduce a denial of service vulnerability: 125 126 foo.send(params[:bar]) # params[:bar] is "exit!" 127 128If an attacker can control the first two arguments to +send+, remote code 129execution is possible: 130 131 # params is { :a => "eval", :b => "...ruby code to be executed..." } 132 foo.send(params[:a], params[:b]) 133 134When dispatching a method call based on user input, carefully verify that the 135method name. If possible, check it against a whitelist of safe method names. 136 137Note that the use of +public_send+ is also dangerous, as +send+ itself is 138public: 139 140 1.public_send("send", "eval", "...ruby code to be executed...") 141 142== DRb 143 144As DRb allows remote clients to invoke arbitrary methods, it is not suitable to 145expose to untrusted clients. 146 147When using DRb, try to avoid exposing it over the network if possible. If this 148isn't possible and you need to expose DRb to the world, you *must* configure an 149appropriate security policy with <code>DRb::ACL</code>. 150