class ActionDispatch::RemoteIp

sometime before this middleware runs.
care about that, then you need to explicitly drop or ignore those headers
claim to have any IP address by setting the X-Forwarded-For header. If you
a proxy, because you are hosted on e.g. Heroku without SSL, any client can
and setting headers with the client’s remote IP address. If you don’t use
This middleware assumes that there is at least one proxy sitting around
IF YOU DON’T USE A PROXY, THIS MAKES YOU VULNERABLE TO IP SPOOFING.
then you should test your Rack server to make sure your data is good.
If you are behind multiple proxy servers (like NGINX to HAProxy to Unicorn)
the value that was given in the last header.
requires. Some Rack servers simply drop preceding headers, and only report
Some Rack servers concatenate repeated headers, like {HTTP RFC 2616}[https://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2]

at GetIp#calculate_ip.
by @gingerlime. A more detailed explanation of the algorithm is given
with reasoning explained at length}[https://blog.gingerlime.com/2012/rails-ip-spoofing-vulnerabilities-and-protection]<br>{the Tomcat server,
on the list of trusted IPs. This follows the precedent set by e.g.
contain the address, and then picking the last-set address that is not
making the request. It does this by checking various headers that could
This middleware calculates the IP address of the remote client that is

def call(env)

GetIp#calculate_ip method will calculate the memoized client IP address.
requests. For those requests that do need to know the IP, the
without calculating the IP to keep from slowing down the majority of
Since the IP address may not be needed, we store the object here
def call(env)
  req = ActionDispatch::Request.new env
  req.remote_ip = GetIp.new(req, check_ip, proxies)
  @app.call(req.env)
end

def initialize(app, ip_spoofing_check = true, custom_proxies = nil)

ignore those IP addresses, and return the one that you want.
them in via the +custom_proxies+ parameter. That way, the middleware will
with your proxy servers after it. If your proxies aren't removed, pass
want in the middle (or at the beginning) of the +X-Forwarded-For+ list,
instead of +TRUSTED_PROXIES+. Any proxy setup will put the value you
The +custom_proxies+ argument can take an enumerable which will be used

incorrect or confusing way (like AWS ELB).
clients (like WAP devices), or behind proxies that set headers in an
address. It makes sense to turn off this check on sites aimed at non-IP
is raised if it looks like the client is trying to lie about its own IP
The +ip_spoofing_check+ option is on by default. When on, an exception

Create a new +RemoteIp+ middleware instance.
def initialize(app, ip_spoofing_check = true, custom_proxies = nil)
  @app = app
  @check_ip = ip_spoofing_check
  @proxies = if custom_proxies.blank?
    TRUSTED_PROXIES
  elsif custom_proxies.respond_to?(:any?)
    custom_proxies
  else
    ActiveSupport::Deprecation.warn(<<~EOM)
      Setting config.action_dispatch.trusted_proxies to a single value has
      been deprecated. Please set this to an enumerable instead. For
      example, instead of:
      config.action_dispatch.trusted_proxies = IPAddr.new("10.0.0.0/8")
      Wrap the value in an Array:
      config.action_dispatch.trusted_proxies = [IPAddr.new("10.0.0.0/8")]
      Note that unlike passing a single argument, passing an enumerable
      will *replace* the default set of trusted proxies.
    EOM
    Array(custom_proxies) + TRUSTED_PROXIES
  end
end