Ruby on Rails | Screencasts | Download | Documentation | Weblog | Community | Source

Changeset 9125 for branches

Show
Ignore:
Timestamp:
03/28/08 21:50:12 (3 months ago)
Author:
bitsweat
Message:

Merge [9124] from trunk: Avoid remote_ip spoofing.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • branches/2-0-stable/actionpack/CHANGELOG

    r8842 r9125  
    11*SVN* 
     2 
     3* Avoid remote_ip spoofing.  [Brian Candler] 
    24 
    35* Correct inconsistencies in RequestForgeryProtection docs.  #11032 [mislav] 
  • branches/2-0-stable/actionpack/lib/action_controller/request.rb

    r8814 r9125  
    123123    alias xhr? :xml_http_request? 
    124124 
     125    # Which IP addresses are "trusted proxies" that can be stripped from 
     126    # the right-hand-side of X-Forwarded-For 
     127    TRUSTED_PROXIES = /^127\.0\.0\.1$|^(10|172\.(1[6-9]|2[0-9]|30|31)|192\.168)\./i 
     128 
    125129    # Determine originating IP address.  REMOTE_ADDR is the standard 
    126130    # but will fail if the user is behind a proxy.  HTTP_CLIENT_IP and/or 
    127     # HTTP_X_FORWARDED_FOR are set by proxies so check for these before 
    128     # falling back to REMOTE_ADDR.  HTTP_X_FORWARDED_FOR may be a comma- 
    129     # delimited list in the case of multiple chained proxies; the first is 
    130     # the originating IP. 
    131     # 
    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. 
     131    # HTTP_X_FORWARDED_FOR are set by proxies so check for these if 
     132    # REMOTE_ADDR is a proxy.  HTTP_X_FORWARDED_FOR may be a comma- 
     133    # delimited list in the case of multiple chained proxies; the last 
     134    # address which is not trusted is the originating IP. 
     135 
    136136    def remote_ip 
    137       return @env['HTTP_CLIENT_IP'] if @env.include? 'HTTP_CLIENT_IP' 
     137      if TRUSTED_PROXIES !~ @env['REMOTE_ADDR'] 
     138        return @env['REMOTE_ADDR'] 
     139      end 
     140 
     141      if @env.include? 'HTTP_CLIENT_IP' 
     142        if @env.include? 'HTTP_X_FORWARDED_FOR' 
     143          # We don't know which came from the proxy, and which from the user 
     144          raise ActionControllerError.new(<<EOM) 
     145IP spoofing attack?! 
     146HTTP_CLIENT_IP=#{@env['HTTP_CLIENT_IP'].inspect} 
     147HTTP_X_FORWARDED_FOR=#{@env['HTTP_X_FORWARDED_FOR'].inspect} 
     148EOM 
     149        end 
     150        return @env['HTTP_CLIENT_IP'] 
     151      end 
    138152 
    139153      if @env.include? 'HTTP_X_FORWARDED_FOR' then 
    140         remote_ips = @env['HTTP_X_FORWARDED_FOR'].split(',').reject do |ip| 
    141           ip.strip =~ /^unknown$|^(10|172\.(1[6-9]|2[0-9]|30|31)|192\.168)\./i 
    142         end 
    143  
    144         return remote_ips.first.strip unless remote_ips.empty? 
     154        remote_ips = @env['HTTP_X_FORWARDED_FOR'].split(',') 
     155        while remote_ips.size > 1 && TRUSTED_PROXIES =~ remote_ips.last.strip 
     156          remote_ips.pop 
     157        end 
     158 
     159        return remote_ips.last.strip 
    145160      end 
    146161 
  • branches/2-0-stable/actionpack/test/controller/request_test.rb

    r8814 r9125  
    1414 
    1515    @request.env['HTTP_CLIENT_IP'] = '2.3.4.5' 
     16    assert_equal '1.2.3.4', @request.remote_ip 
     17 
     18    @request.remote_addr = '192.168.0.1' 
    1619    assert_equal '2.3.4.5', @request.remote_ip 
    1720    @request.env.delete 'HTTP_CLIENT_IP' 
    1821 
     22    @request.remote_addr = '1.2.3.4' 
     23    @request.env['HTTP_X_FORWARDED_FOR'] = '3.4.5.6' 
     24    assert_equal '1.2.3.4', @request.remote_ip 
     25 
     26    @request.remote_addr = '127.0.0.1' 
    1927    @request.env['HTTP_X_FORWARDED_FOR'] = '3.4.5.6' 
    2028    assert_equal '3.4.5.6', @request.remote_ip 
     
    3644 
    3745    @request.env['HTTP_X_FORWARDED_FOR'] = '127.0.0.1,3.4.5.6' 
    38     assert_equal '127.0.0.1', @request.remote_ip 
     46    assert_equal '3.4.5.6', @request.remote_ip 
    3947 
    4048    @request.env['HTTP_X_FORWARDED_FOR'] = 'unknown,192.168.0.1' 
    41     assert_equal '1.2.3.4', @request.remote_ip 
     49    assert_equal 'unknown', @request.remote_ip 
     50 
     51    @request.env['HTTP_X_FORWARDED_FOR'] = '9.9.9.9, 3.4.5.6, 10.0.0.1, 172.31.4.4' 
     52    assert_equal '3.4.5.6', @request.remote_ip 
     53 
     54    @request.env['HTTP_CLIENT_IP'] = '8.8.8.8' 
     55    e = assert_raises(ActionController::ActionControllerError) { 
     56      @request.remote_ip 
     57    } 
     58    assert_match /IP spoofing attack/, e.message 
     59    assert_match /HTTP_X_FORWARDED_FOR="9.9.9.9, 3.4.5.6, 10.0.0.1, 172.31.4.4"/, e.message 
     60    assert_match /HTTP_CLIENT_IP="8.8.8.8"/, e.message 
     61 
     62    @request.env.delete 'HTTP_CLIENT_IP' 
    4263    @request.env.delete 'HTTP_X_FORWARDED_FOR' 
    4364  end