You are here: Home > Latest news from Darcs > Imports changes from Rails' revision r9125

Revision 20080402011408-49d33-de0885...

Imports changes from Rails' revision r9125

vendor/rails/actionpack/CHANGELOG
vendor/rails/actionpack/lib/action_controller/request.rb
vendor/rails/actionpack/test/controller/request_test.rb

Changes to CHANGELOG

1
*SVN*
*SVN*
1
2
2
 
* Avoid remote_ip spoofing.  [Brian Candler]
3
 
4
3
* Correct inconsistencies in RequestForgeryProtection docs.  #11032 [mislav]
* Correct inconsistencies in RequestForgeryProtection docs.  #11032 [mislav]
5
4
6
5
* Make assert_routing aware of the HTTP method used.  #8039 [mpalmer]
* Make assert_routing aware of the HTTP method used.  #8039 [mpalmer]
7

Changes to request.rb

122
    end
    end
122
123
    alias xhr? :xml_http_request?
    alias xhr? :xml_http_request?
123
124
124
 
    # Which IP addresses are "trusted proxies" that can be stripped from
125
 
    # the right-hand-side of X-Forwarded-For
126
 
    TRUSTED_PROXIES = /^127\.0\.0\.1$|^(10|172\.(1[6-9]|2[0-9]|30|31)|192\.168)\./i
127
 
128
125
    # Determine originating IP address.  REMOTE_ADDR is the standard
    # Determine originating IP address.  REMOTE_ADDR is the standard
129
126
    # but will fail if the user is behind a proxy.  HTTP_CLIENT_IP and/or
    # but will fail if the user is behind a proxy.  HTTP_CLIENT_IP and/or
130
127
    # HTTP_X_FORWARDED_FOR are set by proxies so check for these before
    # HTTP_X_FORWARDED_FOR are set by proxies so check for these if
131
128
    # falling back to REMOTE_ADDR.  HTTP_X_FORWARDED_FOR may be a comma-
    # REMOTE_ADDR is a proxy.  HTTP_X_FORWARDED_FOR may be a comma-
132
129
    # delimited list in the case of multiple chained proxies; the first is
    # delimited list in the case of multiple chained proxies; the last
133
130
    # the originating IP.
    # address which is not trusted is the originating IP.
134
131
    #
135
132
    # Security note: do not use if IP spoofing is a concern for your
 
133
    # application. Since remote_ip checks HTTP headers for addresses forwarded
 
134
    # by proxies, the client may send any IP. remote_addr can't be spoofed but
 
135
    # also doesn't work behind a proxy, since it's always the proxy's IP.
 
136
    def remote_ip
    def remote_ip
136
137
      return @env['HTTP_CLIENT_IP'] if @env.include? 'HTTP_CLIENT_IP'
      if TRUSTED_PROXIES !~ @env['REMOTE_ADDR']
137
 
        return @env['REMOTE_ADDR']
138
 
      end
139
 
140
 
      if @env.include? 'HTTP_CLIENT_IP'
141
 
        if @env.include? 'HTTP_X_FORWARDED_FOR'
142
 
          # We don't know which came from the proxy, and which from the user
143
 
          raise ActionControllerError.new(<<EOM)
144
 
IP spoofing attack?!
145
 
HTTP_CLIENT_IP=#{@env['HTTP_CLIENT_IP'].inspect}
146
 
HTTP_X_FORWARDED_FOR=#{@env['HTTP_X_FORWARDED_FOR'].inspect}
147
 
EOM
148
 
        end
149
 
        return @env['HTTP_CLIENT_IP']
150
 
      end
151
138
152
139
      if @env.include? 'HTTP_X_FORWARDED_FOR' then
      if @env.include? 'HTTP_X_FORWARDED_FOR' then
153
140
        remote_ips = @env['HTTP_X_FORWARDED_FOR'].split(',').reject do |ip|
        remote_ips = @env['HTTP_X_FORWARDED_FOR'].split(',')
154
141
          ip.strip =~ /^unknown$|^(10|172\.(1[6-9]|2[0-9]|30|31)|192\.168)\./i
        while remote_ips.size > 1 && TRUSTED_PROXIES =~ remote_ips.last.strip
155
 
          remote_ips.pop
156
142
        end
        end
157
143
158
144
        return remote_ips.first.strip unless remote_ips.empty?
        return remote_ips.last.strip
159
145
      end
      end
160
146
161
147
      @env['REMOTE_ADDR']
      @env['REMOTE_ADDR']
162

Changes to request_test.rb

13
    assert_equal '1.2.3.4', @request.remote_ip
    assert_equal '1.2.3.4', @request.remote_ip
13
14
14
15
    @request.env['HTTP_CLIENT_IP'] = '2.3.4.5'
    @request.env['HTTP_CLIENT_IP'] = '2.3.4.5'
15
 
    assert_equal '1.2.3.4', @request.remote_ip
16
 
17
 
    @request.remote_addr = '192.168.0.1'
18
16
    assert_equal '2.3.4.5', @request.remote_ip
    assert_equal '2.3.4.5', @request.remote_ip
19
17
    @request.env.delete 'HTTP_CLIENT_IP'
    @request.env.delete 'HTTP_CLIENT_IP'
20
18
21
 
    @request.remote_addr = '1.2.3.4'
22
 
    @request.env['HTTP_X_FORWARDED_FOR'] = '3.4.5.6'
23
 
    assert_equal '1.2.3.4', @request.remote_ip
24
 
25
 
    @request.remote_addr = '127.0.0.1'
26
19
    @request.env['HTTP_X_FORWARDED_FOR'] = '3.4.5.6'
    @request.env['HTTP_X_FORWARDED_FOR'] = '3.4.5.6'
27
20
    assert_equal '3.4.5.6', @request.remote_ip
    assert_equal '3.4.5.6', @request.remote_ip
28
21
29
13 more lines
35
    assert_equal '3.4.5.6', @request.remote_ip
    assert_equal '3.4.5.6', @request.remote_ip
43
36
44
37
    @request.env['HTTP_X_FORWARDED_FOR'] = '127.0.0.1,3.4.5.6'
    @request.env['HTTP_X_FORWARDED_FOR'] = '127.0.0.1,3.4.5.6'
45
38
    assert_equal '127.0.0.1', @request.remote_ip
    assert_equal '3.4.5.6', @request.remote_ip
46
39
47
40
    @request.env['HTTP_X_FORWARDED_FOR'] = 'unknown,192.168.0.1'
    @request.env['HTTP_X_FORWARDED_FOR'] = 'unknown,192.168.0.1'
48
41
    assert_equal '1.2.3.4', @request.remote_ip
    assert_equal 'unknown', @request.remote_ip
49
 
50
 
    @request.env['HTTP_X_FORWARDED_FOR'] = '9.9.9.9, 3.4.5.6, 10.0.0.1, 172.31.4.4'
51
 
    assert_equal '3.4.5.6', @request.remote_ip
52
 
53
 
    @request.env['HTTP_CLIENT_IP'] = '8.8.8.8'
54
 
    e = assert_raises(ActionController::ActionControllerError) {
55
 
      @request.remote_ip
56
 
    }
57
 
    assert_match /IP spoofing attack/, e.message
58
 
    assert_match /HTTP_X_FORWARDED_FOR="9.9.9.9, 3.4.5.6, 10.0.0.1, 172.31.4.4"/, e.message
59
 
    assert_match /HTTP_CLIENT_IP="8.8.8.8"/, e.message
60
 
61
 
    @request.env.delete 'HTTP_CLIENT_IP'
62
42
    @request.env.delete 'HTTP_X_FORWARDED_FOR'
    @request.env.delete 'HTTP_X_FORWARDED_FOR'
63
43
  end
  end
64
44
65