Is it secure to rely on “X-Forwarded-For” to restrict access by IP in Apache while using Cloudflare?

回眸只為那壹抹淺笑 提交于 2020-08-23 12:34:04

问题


I'm restricting access to a directory to certain IP addresses using a .htaccess file like this:

AuthType Basic
AuthName "Protected"

<RequireAny>
    Require ip 1.2.3.4
</RequireAny>

That works fine in a normal server setup, however when using Cloudflare as a WAF proxy, it stops working since the server receives all requests proxied through Cloudflare's IP.

As a workaround, it's possible to use the "X-Forwarded-For" header to identify the client's "real" IP address, since Cloudflare passes this with all its requests:

AuthType Basic
AuthName "Protected"

SetEnvIf X-Forwarded-For 1.2.3.4$ allowed

<RequireAny>
    Require env allowed
</RequireAny>

Is this a safe approach or is there a better/more secure way to limit access by client IP in Apache when Cloudflare is being used?


回答1:


According to the IETF RFC 2616, Section 4.2, a header can hold a comma separated list of values, and this is the case of X-Forwarded-For as Cloudflare uses it.

If an X-Forwarded-For header was already present in the request to Cloudflare, Cloudflare appends the IP address of the HTTP proxy to the header:

Example: X-Forwarded-For: 203.0.113.1,198.51.100.101,198.51.100.102 

In the examples above, 203.0.113.1 is the original visitor IP address and 198.51.100.101 and 198.51.100.102 are proxy server IP addresses provided to Cloudflare via the X-Forwarded-For header.

It is customary to take the leftmost IP as the real one, but this isn't always the case.

If you go this way, you should check for a regex that matches your IP as

SetEnvIf X-Forwarded-For ^1\.2\.3\.4 allowed

(leftmost IP, escaping the dots)

A better way (IMHO)

Cloudflare also sends the header cf-connecting-ip (which is meant to be the last IP to hit cloudflare before being sent to your machine) and I'd rather use that one.

Is this a safe approach or is there a better/more secure way to limit access by client IP in Apache when Cloudflare is being used?

There's a catch. In this scenario, you're telling Apache:

"we have cloudflare in the middle so instead of your native way to tell the visitor's IP let's look at this custom header".

That custom header can be forged. Absolutely. Therefore, you should also say:

"this custom header should be taken as reliable if and only the request comes from a Cloudflare IP".

Cloudflare does explicitly list their IP ranges

Finally, you should use mod_remoteip instead of manually building a SetEnvIf rule.

Basically:

# /etc/apache2/conf-enabled/remoteip.conf
RemoteIPHeader CF-Connecting-IP
RemoteIPTrustedProxy 173.245.48.0/20
RemoteIPTrustedProxy 103.21.244.0/22
...
RemoteIPTrustedProxy 2606:4700::/32
RemoteIPTrustedProxy 2803:f800::/32

Alternatively, put the IP list in a separate file:

# /etc/apache2/conf-enabled/remoteip.conf
RemoteIPHeader CF-Connecting-IP
RemoteIPTrustedProxyList conf/trusted-proxies.lst

and

# conf/trusted-proxies.lst
173.245.48.0/20
103.21.244.0/22
...
...
2803:f800::/32
2606:4700::/32

If said header doesn't come in the request, Apache falls back ro REMOTE_ADDR. Same goes for requests coming from untrusted IPs. If the header is present and comes from Cloudflare, you can simply do:

Require ip 1.2.3.4

This approach replaces the IP wherever you need to use it (logs, auth, etc) and gracefully falls back to original REMOTE_ADDR in edge cases.



来源:https://stackoverflow.com/questions/58314261/is-it-secure-to-rely-on-x-forwarded-for-to-restrict-access-by-ip-in-apache-whi

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!