diff options
author | MrBrdo <mrbrdo@gmail.com> | 2012-06-08 00:08:51 +0200 |
---|---|---|
committer | Jan Berdajs <mrbrdo@gmail.com> | 2012-06-14 18:10:49 +0200 |
commit | bc7c0b5c108ef47b24bb91c502429935bb34d214 (patch) | |
tree | 8080f11a0fa497eec595df065894f36b2db1a8af /guides/source | |
parent | f278b067891b3a3e3462e92ada72e8dc5f24797b (diff) | |
download | rails-bc7c0b5c108ef47b24bb91c502429935bb34d214.tar.gz rails-bc7c0b5c108ef47b24bb91c502429935bb34d214.tar.bz2 rails-bc7c0b5c108ef47b24bb91c502429935bb34d214.zip |
prevent users from unknowingly using bad regexps that can compromise security (http://homakov.blogspot.co.uk/2012/05/saferweb-injects-in-various-ruby.html)
Diffstat (limited to 'guides/source')
-rw-r--r-- | guides/source/active_model_basics.textile | 2 | ||||
-rw-r--r-- | guides/source/security.textile | 33 |
2 files changed, 26 insertions, 9 deletions
diff --git a/guides/source/active_model_basics.textile b/guides/source/active_model_basics.textile index d373f4ac85..7cafff2ad8 100644 --- a/guides/source/active_model_basics.textile +++ b/guides/source/active_model_basics.textile @@ -187,7 +187,7 @@ class Person attr_accessor :name, :email, :token validates :name, :presence => true - validates_format_of :email, :with => /^([^\s]+)((?:[-a-z0-9]\.)[a-z]{2,})$/i + validates_format_of :email, :with => /\A([^\s]+)((?:[-a-z0-9]\.)[a-z]{2,})\z/i validates! :token, :presence => true end diff --git a/guides/source/security.textile b/guides/source/security.textile index 0931dd6393..626d6fa508 100644 --- a/guides/source/security.textile +++ b/guides/source/security.textile @@ -588,26 +588,43 @@ h4. Regular Expressions INFO: _A common pitfall in Ruby's regular expressions is to match the string's beginning and end by ^ and $, instead of \A and \z._ -Ruby uses a slightly different approach than many other languages to match the end and the beginning of a string. That is why even many Ruby and Rails books make this wrong. So how is this a security threat? Imagine you have a File model and you validate the file name by a regular expression like this: +Ruby uses a slightly different approach than many other languages to match the end and the beginning of a string. That is why even many Ruby and Rails books make this wrong. So how is this a security threat? Say you wanted to loosely validate a URL field and you used a simple regular expression like this: <ruby> -class File < ActiveRecord::Base - validates :name, :format => /^[\w\.\-\<plus>]<plus>$/ -end + /^https?:\/\/[^\n]+$/i </ruby> -This means, upon saving, the model will validate the file name to consist only of alphanumeric characters, dots, + and -. And the programmer added ^ and $ so that file name will contain these characters from the beginning to the end of the string. However, _(highlight)in Ruby ^ and $ matches the *line* beginning and line end_. And thus a file name like this passes the filter without problems: +This may work fine in some languages. However, _(highlight)in Ruby ^ and $ match the *line* beginning and line end_. And thus a URL like this passes the filter without problems: <plain> -file.txt%0A<script>alert('hello')</script> +javascript:exploit_code();/* +http://hi.com +*/ </plain> -Whereas %0A is a line feed in URL encoding, so Rails automatically converts it to "file.txt\n<script>alert('hello')</script>". This file name passes the filter because the regular expression matches – up to the line end, the rest does not matter. The correct expression should read: +This URL passes the filter because the regular expression matches – the second line, the rest does not matter. Now imagine we had a view that showed the URL like this: + +<ruby> + link_to "Homepage", @user.homepage +</ruby> + +The link looks innocent to visitors, but when it's clicked, it will execute the javascript function "exploit_code" or any other javascript the attacker provides. + +To fix the regular expression, \A and \z should be used instead of ^ and $, like so: <ruby> -/\A[\w\.\-\<plus>]<plus>\z/ + /\Ahttps?:\/\/[^\n]+\z/i </ruby> +Since this is a frequent mistake, the format validator (validates_format_of) now raises an exception if the provided regular expression starts with ^ or ends with $. If you do need to use ^ and $ instead of \A and \z (which is rare), you can set the :multiline option to true, like so: + +<ruby> + # content should include a line "Meanwhile" anywhere in the string + validates :content, :format => { :with => /^Meanwhile$/, :multiline => true } +</ruby> + +Note that this only protects you against the most common mistake when using the format validator - you always need to keep in mind that ^ and $ match the *line* beginning and line end in Ruby, and not the beginning and end of a string. + h4. Privilege Escalation WARNING: _Changing a single parameter may give the user unauthorized access. Remember that every parameter may be changed, no matter how much you hide or obfuscate it._ |