LoginSignup
54
27

More than 3 years have passed since last update.

railsにおけるremote_ipって何が嬉しいのだろうか?

Last updated at Posted at 2015-03-25

grapeとか使ってアレレ?ってなったのでまとめました。

request.remote_ip method in rails

action_dispatch.remote_ip、なかったらipを引っ張る。

# File actionpack/lib/action_dispatch/http/request.rb, line 230
def remote_ip
  @remote_ip ||= (@env["action_dispatch.remote_ip"] || ip).to_s
end

grapeとか組み合わせる時以外はaction_dispatch.remote_ipが無いなんてことはないんじゃないだろうか。
とりあえずip側から調べます。

request#ip

# File actionpack/lib/action_dispatch/http/request.rb, line 225
def ip
  @ip ||= super
end

rackのipをcallするだけ。rack側ではこんな感じで

    def ip
      remote_addrs = split_ip_addresses(@env['REMOTE_ADDR'])
      remote_addrs = reject_trusted_ip_addresses(remote_addrs)

      return remote_addrs.first if remote_addrs.any?

      forwarded_ips = split_ip_addresses(@env['HTTP_X_FORWARDED_FOR'])

      return reject_trusted_ip_addresses(forwarded_ips).last || @env["REMOTE_ADDR"]
    end

    def trusted_proxy?(ip)
      ip =~ /\A127\.0\.0\.1\Z|\A(10|172\.(1[6-9]|2[0-9]|30|31)|192\.168)\.|\A::1\Z|\Afd[0-9a-f]{2}:.+|\Alocalhost\Z|\Aunix\Z|\Aunix:/i
    end

    protected
      def reject_trusted_ip_addresses(ip_addresses)
        ip_addresses.reject { |ip| trusted_proxy?(ip) }
      end

  1. REMOTE_ADDRをみてlocal系を省いて、IP残ってたらそれ返す。
  2. そうじゃなかったらHTTP_X_FORWARDED_FORをみて一番最初のものをみる。

これだけなのね、シンプル。

action_dispatch.remote_ip

こっち側はちょっと複雑でこんな感じ

      def calculate_ip
        # Set by the Rack web server, this is a single value.
        remote_addr = ips_from('REMOTE_ADDR').last

        # Could be a CSV list and/or repeated headers that were concatenated.
        client_ips    = ips_from('HTTP_CLIENT_IP').reverse
        forwarded_ips = ips_from('HTTP_X_FORWARDED_FOR').reverse

        # +Client-Ip+ and +X-Forwarded-For+ should not, generally, both be set.
        # If they are both set, it means that this request passed through two
        # proxies with incompatible IP header conventions, and there is no way
        # for us to determine which header is the right one after the fact.
        # Since we have no idea, we give up and explode.
        should_check_ip = @check_ip && client_ips.last && forwarded_ips.last
        if should_check_ip && !forwarded_ips.include?(client_ips.last)
          # We don't know which came from the proxy, and which from the user
          raise IpSpoofAttackError, "IP spoofing attack?! " +
            "HTTP_CLIENT_IP=#{@env['HTTP_CLIENT_IP'].inspect} " +
            "HTTP_X_FORWARDED_FOR=#{@env['HTTP_X_FORWARDED_FOR'].inspect}"
        end

        # We assume these things about the IP headers:
        #
        #   - X-Forwarded-For will be a list of IPs, one per proxy, or blank
        #   - Client-Ip is propagated from the outermost proxy, or is blank
        #   - REMOTE_ADDR will be the IP that made the request to Rack
        ips = [forwarded_ips, client_ips, remote_addr].flatten.compact

        # If every single IP option is in the trusted list, just return REMOTE_ADDR
        filter_proxies(ips).first || remote_addr
      end

REMOTE_ADDR、
1. HTTP_X_FORWARDED_FORのリバース、HTTP_CLIENT_IPのリバース、REMOTE_ADDRの順で配列作って
2. rack側と同じようにtrustedなアドレスを取り除いて
- https://github.com/rails/rails/blob/a59a9b7f729870de6c9282bd8e2a7ed7f86fc868/actionpack/lib/action_dispatch/middleware/remote_ip.rb#L33
3. 最初の返す
4. REMOTE_ADDRをそのまま返す

ほとんど同じですね。

ipとremote_ipの違いは?

違いとしては二つ

  1. HTTP_CLIENT_IPをIPアドレス選択のヒエラルキーに含むことができる。
  2. trustedなアドレスリストをカスタムできる

1. HTTP_CLIENT_IP

うーむ。そもそもHTTP_CLIENT_IPとHTTP_X_FORWARDED_FORの違いってなんなの?って思って調べたらまさにそのまま。

超意訳すると

  1. 実装の違いで同じ意味
  2. 値が違うのは、HTTP_X_FORWARDED_FORはproxyされたip全部トラッキングするけど、clinet_ipは1個しか入れないからだね。

とするとこれは別に嬉しくない気がする。

2. trustedなアドレスリストをカスタム

これがすごい嬉しいかというと、どうなのだろう。よく分からない。

54
27
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
54
27