class ActionDispatch::RemoteIp
relying on it.
middleware runs. Alternatively, remove this middleware to avoid inadvertently
you need to explicitly drop or ignore those headers sometime before this
address by setting the ‘X-Forwarded-For` header. If you care about that, then
you are hosted on e.g. Heroku without SSL, any client can claim to have any IP
headers with the client’s remote IP address. If you don’t use a proxy, because
middleware assumes that there is at least one proxy sitting around and setting
IF YOU DON’T USE A PROXY, THIS MAKES YOU VULNERABLE TO IP SPOOFING. This
Unicorn) 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
header](andre.arko.net/2011/12/26/repeated-headers-and-ruby-web-servers).
that was [given in the last
Some Rack servers simply drop preceding headers, and only report the value
2616](www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2) requires.
Some Rack servers concatenate repeated headers, like [HTTP RFC
detailed explanation of the algorithm is given at GetIp#calculate_ip.
server](issues.apache.org/bugzilla/show_bug.cgi?id=50453). A more
trusted IPs. This follows the precedent set by e.g. [the Tomcat
address, and then picking the last-set address that is not on the list of
the request. It does this by checking various headers that could contain the
This middleware calculates the IP address of the remote client that is making
# Action Dispatch RemoteIp
def call(env)
those requests that do need to know the IP, the GetIp#calculate_ip method will
calculating the IP to keep from slowing down the majority of requests. For
Since the IP address may not be needed, we store the object here without
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)
`custom_proxies` parameter. That way, the middleware will ignore those IP
proxy servers after it. If your proxies aren't removed, pass them in via the
the middle (or at the beginning) of the `X-Forwarded-For` list, with your
instead of `TRUSTED_PROXIES`. Any proxy setup will put the value you want in
The `custom_proxies` argument can take an enumerable which will be used
way (like AWS ELB).
WAP devices), or behind proxies that set headers in an incorrect or confusing
It makes sense to turn off this check on sites aimed at non-IP clients (like
raised if it looks like the client is trying to lie about its own IP address.
The `ip_spoofing_check` option is on by default. When on, an exception is
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 raise(ArgumentError, <<~EOM) Setting config.action_dispatch.trusted_proxies to a single value isn't supported. 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 passing an enumerable will *replace* the default set of trusted proxies. EOM end end