1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Rails - request.remote_ip / request.remote_addr の違い ( Proxy サーバー・ロードバランサーがリクエストの間にある場合 )

Last updated at Posted at 2025-05-21

概要

Rails の request.remote_ip はリクエストに Proxyサーバー・ロードバランサーを挟む場合でも「良い感じ」で「元のIPアドレス」の推定をしてくれそう

このあたりのコードを読むと action_dispatch.remote_ip というものが呼び出されている

    # Originating IP address, usually set by the RemoteIp middleware.
    def remote_ip
      @remote_ip ||= (@env["action_dispatch.remote_ip"] || ip).to_s
    end

その先を読むと
https://github.com/rails/rails/blob/main/actionpack/lib/action_dispatch/middleware/remote_ip.rb#L109C1-L126C64

      # Sort through the various IP address headers, looking for the IP most likely to
      # be the address of the actual remote client making this request.
      #
      # REMOTE_ADDR will be correct if the request is made directly against the Ruby
      # process, on e.g. Heroku. When the request is proxied by another server like
      # HAProxy or NGINX, the IP address that made the original request will be put in
      # an `X-Forwarded-For` header. If there are multiple proxies, that header may
      # contain a list of IPs. Other proxy services set the `Client-Ip` header
      # instead, so we check that too.
      #
      # As discussed in [this post about Rails IP
      # Spoofing](https://web.archive.org/web/20170626095448/https://blog.gingerlime.com/2012/rails-ip-spoofing-vulnerabilities-and-protection/),
      # while the first IP in the list is likely to be the "originating" IP, it
      # could also have been set by the client maliciously.
      #
      # In order to find the first address that is (probably) accurate, we take the
      # list of IPs, remove known and trusted proxies, and then take the last address
      # left, which was presumably set by one of those proxies.

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

        # Could be a CSV list and/or repeated headers that were concatenated.
        client_ips    = ips_from(@req.client_ip).reverse!
        forwarded_ips = ips_from(@req.x_forwarded_for).reverse!

        # `Client-Ip` and `X-Forwarded-For` should not, generally, both be set. If they
        # are both set, it means that either:
        #
        # 1) This request passed through two proxies with incompatible IP header
        #     conventions.
        #
        # 2) The client passed one of `Client-Ip` or `X-Forwarded-For`
        #     (whichever the proxy servers weren't using) themselves.
        #
        # Either way, there is no way for us to determine which header is the right one
        # after the fact. Since we have no idea, if we are concerned about IP spoofing
        # we need to give up and explode. (If you're not concerned about IP spoofing you
        # can turn the `ip_spoofing_check` option off.)
        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=#{@req.client_ip.inspect} " \
            "HTTP_X_FORWARDED_FOR=#{@req.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
        ips.compact!

        # If every single IP option is in the trusted list, return the IP that's
        # furthest away
        filter_proxies(ips + [remote_addr]).first || ips.last || remote_addr
      end

Trusted Proxy

Railsはデフォルトで「信頼できるプロクシ」の一覧を持っているようだ

    # The default trusted IPs list simply includes IP addresses that are guaranteed
    # by the IP specification to be private addresses. Those will not be the
    # ultimate client IP in production, and so are discarded. See
    # https://en.wikipedia.org/wiki/Private_network for details.
    TRUSTED_PROXIES = [
      "127.0.0.0/8",    # localhost IPv4 range, per RFC-3330
      "::1",            # localhost IPv6
      "fc00::/7",       # private IPv6 range fc00::/7
      "10.0.0.0/8",     # private IPv4 range 10.x.x.x
      "172.16.0.0/12",  # private IPv4 range 172.16.0.0 .. 172.31.255.255
      "192.168.0.0/16", # private IPv4 range 192.168.x.x
    ].map { |proxy| IPAddr.new(proxy) }

なので、ロードバランサーが間にある構成でも、ロードバランサーが自己申告した HTTP_X_FORWARDED_FOR を信頼して request.remote_ip の値として返してくれていそうだ

Trusted Proxy の設定

なおRails config で trustex proxy を指定することもできるようだが、上記の通り、デフォルトでもプライベートのIPアドレスは心されている模様

config.action_dispatch.trusted_proxies

備考

素のIPアドレスを返すのは以下

  • request.remote_addr
  • request.env['REMOTE_ADDR']

HTTP_X_FORWARDED_FOR は以下で確認できる

  • request.env['HTTP_X_FORWARDED_FOR']

リンク

1
0
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
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?