From bc7c0b5c108ef47b24bb91c502429935bb34d214 Mon Sep 17 00:00:00 2001 From: MrBrdo Date: Fri, 8 Jun 2012 00:08:51 +0200 Subject: prevent users from unknowingly using bad regexps that can compromise security (http://homakov.blogspot.co.uk/2012/05/saferweb-injects-in-various-ruby.html) --- activemodel/lib/active_model/validations/format.rb | 23 +++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) (limited to 'activemodel/lib/active_model') diff --git a/activemodel/lib/active_model/validations/format.rb b/activemodel/lib/active_model/validations/format.rb index dd87e312f9..ffdf842d94 100644 --- a/activemodel/lib/active_model/validations/format.rb +++ b/activemodel/lib/active_model/validations/format.rb @@ -32,11 +32,21 @@ module ActiveModel def record_error(record, attribute, name, value) record.errors.add(attribute, :invalid, options.except(name).merge!(:value => value)) end - + + def regexp_using_multiline_anchors?(regexp) + regexp.source.start_with?("^") || + (regexp.source.end_with?("$") && !regexp.source.end_with?("\\$")) + end + def check_options_validity(options, name) option = options[name] if option && !option.is_a?(Regexp) && !option.respond_to?(:call) raise ArgumentError, "A regular expression or a proc or lambda must be supplied as :#{name}" + elsif option && option.is_a?(Regexp) && + regexp_using_multiline_anchors?(option) && options[:multiline] != true + raise ArgumentError, "The provided regular expression is using multiline anchors (^ or $), " \ + "which may present a security risk. Did you mean to use \\A and \\z, or forgot to add the " \ + ":multiline => true option?" end end end @@ -47,7 +57,7 @@ module ActiveModel # attribute matches the regular expression: # # class Person < ActiveRecord::Base - # validates_format_of :email, :with => /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i, :on => :create + # validates_format_of :email, :with => /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i, :on => :create # end # # Alternatively, you can require that the specified attribute does _not_ @@ -63,12 +73,16 @@ module ActiveModel # class Person < ActiveRecord::Base # # Admin can have number as a first letter in their screen name # validates_format_of :screen_name, - # :with => lambda{ |person| person.admin? ? /\A[a-z0-9][a-z0-9_\-]*\Z/i : /\A[a-z][a-z0-9_\-]*\Z/i } + # :with => lambda{ |person| person.admin? ? /\A[a-z0-9][a-z0-9_\-]*\z/i : /\A[a-z][a-z0-9_\-]*\z/i } # end # # Note: use \A and \Z to match the start and end of the # string, ^ and $ match the start/end of a line. # + # Due to frequent misuse of ^ and $, you need to pass the + # :multiline => true option in case you use any of these two anchors in the provided + # regular expression. In most cases, you should be using \A and \z. + # # You must pass either :with or :without as an option. # In addition, both must be a regular expression or a proc or lambda, or # else an exception will be raised. @@ -98,6 +112,9 @@ module ActiveModel # method, proc or string should return or evaluate to a true or false value. # * :strict - Specifies whether validation should be strict. # See ActiveModel::Validation#validates! for more information. + # * :multiline - Set to true if your regular expression contains + # anchors that match the beginning or end of lines as opposed to the + # beginning or end of the string. These anchors are ^ and $. def validates_format_of(*attr_names) validates_with FormatValidator, _merge_attributes(attr_names) end -- cgit v1.2.3