Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Merge remote-tracking branch 'origin/master'
* origin/master:
  Added backport of Ruby URI's 1.9.3 DoS fix
  Regression test for DoS attack on form/cookie param decoding
  • Loading branch information
raggi committed Oct 1, 2011
2 parents 00498d9 + 89c961b commit b25cf63
Show file tree
Hide file tree
Showing 4 changed files with 68 additions and 3 deletions.
File renamed without changes.
54 changes: 54 additions & 0 deletions lib/rack/backports/uri/common_192.rb
@@ -0,0 +1,54 @@
# :stopdoc:

# Stolen from ruby core's uri/common.rb @32618ba to fix DoS issues in 1.9.2
#
# https://github.com/ruby/ruby/blob/32618ba7438a2247042bba9b5d85b5d49070f5e5/lib/uri/common.rb
#
# Issue:
# http://redmine.ruby-lang.org/issues/5149
#
# Relevant Fixes:
# https://github.com/ruby/ruby/commit/b5f91deee04aa6ccbe07c23c8222b937c22a799b
# https://github.com/ruby/ruby/commit/93177c1e5c3906abf14472ae0b905d8b5c72ce1b
#
# This should probably be removed once there is a Ruby 1.9.2 patch level that
# includes this fix.

require 'uri/common'

module URI
def self.decode_www_form(str, enc=Encoding::UTF_8)
return [] if str.empty?
unless /\A#{WFKV_}=#{WFKV_}(?:[;&]#{WFKV_}=#{WFKV_})*\z/o =~ str
raise ArgumentError, "invalid data of application/x-www-form-urlencoded (#{str})"
end
ary = []
$&.scan(/([^=;&]+)=([^;&]*)/) do
ary << [decode_www_form_component($1, enc), decode_www_form_component($2, enc)]
end
ary
end

def self.decode_www_form_component(str, enc=Encoding::UTF_8)
if TBLDECWWWCOMP_.empty?
tbl = {}
256.times do |i|
h, l = i>>4, i&15
tbl['%%%X%X' % [h, l]] = i.chr
tbl['%%%x%X' % [h, l]] = i.chr
tbl['%%%X%x' % [h, l]] = i.chr
tbl['%%%x%x' % [h, l]] = i.chr
end
tbl['+'] = ' '
begin
TBLDECWWWCOMP_.replace(tbl)
TBLDECWWWCOMP_.freeze
rescue
end
end
raise ArgumentError, "invalid %-encoding (#{str})" unless /\A[^%]*(?:%\h\h[^%]*)*\z/ =~ str
str.gsub(/\+|%\h\h/, TBLDECWWWCOMP_).force_encoding(enc)
end

WFKV_ = '(?:[^%#=;&]*(?:%\h\h[^%#=;&]*)*)' # :nodoc:
end
7 changes: 4 additions & 3 deletions lib/rack/utils.rb
Expand Up @@ -6,9 +6,10 @@

major, minor, patch = RUBY_VERSION.split('.').map { |v| v.to_i }

if (major == 1 && minor < 9) || (major == 1 && minor == 9 && patch < 2)
# pull in backports
require 'rack/backports/uri/common'
if major == 1 && minor < 9
require 'rack/backports/uri/common_18'
elsif major == 1 && minor == 9 && patch < 3
require 'rack/backports/uri/common_192'
else
require 'uri/common'
end
Expand Down
10 changes: 10 additions & 0 deletions test/spec_utils.rb
Expand Up @@ -58,6 +58,16 @@ def kcodeu
Rack::Utils.escape("ø".encode("ISO-8859-1")).should.equal "%F8"
end
end

should "not hang on escaping long strings that end in % (http://redmine.ruby-lang.org/issues/5149)" do
lambda {
timeout(1) do
lambda {
URI.decode_www_form_component "A string that causes catastrophic backtracking as it gets longer %"
}.should.raise(ArgumentError)
end
}.should.not.raise(Timeout::Error)
end

should "escape path spaces with %20" do
Rack::Utils.escape_path("foo bar").should.equal "foo%20bar"
Expand Down

0 comments on commit b25cf63

Please sign in to comment.