U:RDoc::TopLevel[ iI"security.rdoc:EFcRDoc::Parser::Simpleo:RDoc::Markup::Document: @parts[[S:RDoc::Markup::Heading: leveli: textI"Ruby Security;To:RDoc::Markup::BlankLineo:RDoc::Markup::Paragraph;[I"TThe Ruby programming language is large and complex and there are many security ;TI"Lpitfalls often encountered by newcomers and experienced Rubyists alike.;T@ o; ;[I"RThis document aims to discuss many of these pitfalls and provide more secure ;TI"#alternatives where applicable.;T@ o; ;[I"UPlease check the full list of publicly known CVEs and how to correctly report a ;TI"Hsecurity vulnerability, at: https://www.ruby-lang.org/en/security/ ;TI"EJapanese version is here: https://www.ruby-lang.org/ja/security/;T@ o; ;[ I"ASecurity vulnerabilities should be reported via an email to ;TI"4mailto:security@ruby-lang.org ({the PGP public ;TI"Ukey}[https://www.ruby-lang.org/security.asc]), which is a private mailing list. ;TI"5Reported problems will be published after fixes.;T@ S; ; i; I"$SAFE;T@ o; ;[I"TRuby provides a mechanism to restrict what operations can be performed by Ruby ;TI"9code in the form of the $SAFE variable.;T@ o; ;[I"UHowever, $SAFE does not provide a secure environment for executing ;TI"untrusted code.;T@ o; ;[ I"UIf you need to execute untrusted code, you should use an operating system level ;TI"Jsandboxing mechanism. On Linux, ptrace or LXC can be used to sandbox ;TI"Opotentially malicious code. Other similar mechanisms exist on every major ;TI"operating system.;T@ S; ; i; I"+Marshal.load+;T@ o; ;[I"URuby's +Marshal+ module provides methods for serializing and deserializing Ruby ;TI"3object trees to and from a binary data format.;T@ o; ;[ I"NNever use +Marshal.load+ to deserialize untrusted or user supplied data. ;TI"NBecause +Marshal+ can deserialize to almost any Ruby object and has full ;TI"Rcontrol over instance variables, it is possible to craft a malicious payload ;TI"6that executes code shortly after deserialization.;T@ o; ;[ I"RIf you need to deserialize untrusted data, you should use JSON as it is only ;TI"Ucapable of returning 'primitive' types such as strings, arrays, hashes, numbers ;TI"Oand nil. If you need to deserialize other classes, you should handle this ;TI";manually. Never deserialize to a user specified class.;T@ S; ; i; I" YAML;T@ o; ;[I"RYAML is a popular human readable data serialization format used by many Ruby ;TI"Nprograms for configuration and database persistence of Ruby object trees.;T@ o; ;[I"RSimilar to +Marshal+, it is able to deserialize into arbitrary Ruby classes. ;TI"KFor example, the following YAML data will create an +ERB+ object when ;TI"deserialized:;T@ o:RDoc::Markup::Verbatim;[I"!ruby/object:ERB ;TI"src: puts `uname` ;T: @format0o; ;[I"RBecause of this, many of the security considerations applying to Marshal are ;TI"Lalso applicable to YAML. Do not use YAML to deserialize untrusted data.;T@ S; ; i; I" Symbols;T@ o; ;[ I"USymbols are often seen as syntax sugar for simple strings, but they play a much ;TI"Pmore crucial role. The MRI Ruby implementation uses Symbols internally for ;TI"Rmethod, variable and constant names. The reason for this is that symbols are ;TI"Ssimply integers with names attached to them, so they are faster to look up in ;TI"hashtables.;T@ o; ;[I"OStarting in version 2.2, most symbols can be garbage collected; these are ;TI"Lcalled mortal symbols. Most symbols you create (e.g. by calling ;TI"+to_sym+) are mortal.;T@ o; ;[I"PImmortal symbols on the other hand will never be garbage collected. ;TI"*They are created when modifying code:;To:RDoc::Markup::List: @type: BULLET: @items[o:RDoc::Markup::ListItem: @label0;[o; ;[I"3defining a method (e.g. with +define_method+),;To;;0;[o; ;[I"Fsetting an instance variable (e.g. with +instance_variable_set+),;To;;0;[o; ;[I"^ and $ anchors do not ;TI"Urefer to the beginning and end of the string, rather the beginning and end of a ;TI" *line*.;T@ o; ;[ I"?This means that if you're using a regular expression like ;TI"S/^[a-z]+$/ to restrict a string to only letters, an attacker can ;TI"Ubypass this check by passing a string containing a letter, then a newline, then ;TI""any string of their choosing.;T@ o; ;[I"RIf you want to match the beginning and end of the entire string in Ruby, use ;TI"the anchors +\A+ and +\z+.;T@ S; ; i; I" +eval+;T@ o; ;[I"=Never pass untrusted or user controlled input to +eval+.;T@ o; ;[ I"NUnless you are implementing a REPL like +irb+ or +pry+, +eval+ is almost ;TI"Ucertainly not what you want. Do not attempt to filter user input before passing ;TI"Sit to +eval+ - this approach is fraught with danger and will most likely open ;TI"Jyour application up to a serious remote code execution vulnerability.;T@ S; ; i; I" +send+;T@ o; ;[I"U'Global functions' in Ruby (+puts+, +exit+, etc.) are actually private instance ;TI"Qmethods on +Object+. This means it is possible to invoke these methods with ;TI"A+send+, even if the call to +send+ has an explicit receiver.;T@ o; ;[I"RFor example, the following code snippet writes "Hello world" to the terminal:;T@ o;;[I""1.send(:puts, "Hello world") ;T;0o; ;[I"SYou should never call +send+ with user supplied input as the first parameter. ;TI">Doing so can introduce a denial of service vulnerability:;T@ o;;[I"6foo.send(params[:bar]) # params[:bar] is "exit!" ;T;0o; ;[I"OIf an attacker can control the first two arguments to +send+, remote code ;TI"execution is possible:;T@ o;;[I"J# params is { :a => "eval", :b => "...ruby code to be executed..." } ;TI"&foo.send(params[:a], params[:b]) ;T;0o; ;[I"SWhen dispatching a method call based on user input, carefully verify that the ;TI"Qmethod name. If possible, check it against a whitelist of safe method names.;T@ o; ;[I"ONote that the use of +public_send+ is also dangerous, as +send+ itself is ;TI" public:;T@ o;;[I"E1.public_send("send", "eval", "...ruby code to be executed...") ;T;0S; ; i; I"DRb;T@ o; ;[I"UAs DRb allows remote clients to invoke arbitrary methods, it is not suitable to ;TI"!expose to untrusted clients.;T@ o; ;[I"TWhen using DRb, try to avoid exposing it over the network if possible. If this ;TI"Uisn't possible and you need to expose DRb to the world, you *must* configure an ;TI"DRb::ACL.;T: @file@:0@omit_headings_from_table_of_contents_below0