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