PascalMinder / geoblock

Traefik middleware plugin - Deny requests based on country of origin
97 stars 10 forks source link

X-Forwarded-For #46

Open fdegraeve opened 7 months ago

fdegraeve commented 7 months ago

Hello,

I have this line of log in Traefik app.

{"ClientAddr":"172.69.195.155:25064","ClientHost":"92.159.32.169","ClientPort":"25064","ClientUsername":"-","DownstreamContentSize":0,"DownstreamStatus":403,"Duration":78683198,"OriginContentSize":0,"OriginDuration":78537041,"OriginStatus":403,"Overhead":146157,"RequestAddr":"HIDE","RequestContentSize":0,"RequestCount":787,"RequestHost":"HIDE","RequestMethod":"GET","RequestPath":"/","RequestPort":"-","RequestProtocol":"HTTP/2.0","RequestScheme":"https","RetryAttempts":0,"RouterName":"ghost@docker","StartLocal":"2023-11-21T14:39:38.552466146+01:00","StartUTC":"2023-11-21T13:39:38.552466146Z","TLSCipher":"TLS_AES_128_GCM_SHA256","TLSVersion":"1.3","downstream_Strict-Transport-Security":"max-age=31536000; includeSubDomains","downstream_Vary":"Accept-Encoding","entryPointName":"websecure","level":"info","msg":"","origin_Strict-Transport-Security":"max-age=31536000; includeSubDomains","origin_Vary":"Accept-Encoding","request_Accept-Encoding":"gzip","request_Cdn-Loop":"cloudflare","request_Cf-Connecting-Ip":"92.159.32.169","request_Cf-Ipcountry":"FR","request_Cf-Ray":"82995705ece16353-LHR","request_Cf-Visitor":"{\"scheme\":\"https\"}","request_User-Agent":"Go-http-client/1.1","request_X-Forwarded-For":"92.159.32.169","request_X-Forwarded-Host":"HIDE","request_X-Forwarded-Port":"443","request_X-Forwarded-Proto":"https","request_X-Forwarded-Server":"7d5c04451a79","request_X-Real-Ip":"172.69.195.155","time":"2023-11-21T14:39:38+01:00"}

And in trafik log

INFO: GeoBlock: 2023/11/21 14:39:38 geoblock@file: request denied [172.69.195.155] for country [LV]

I don't understand it's don't take the IP 92.159.32.169 in X-Forwarded-For, the code look good.

If you have an idea ?

I have this architecture: CLIENT -> Cloudflare -> Server

Thanks for your help :)

I open to help you with test if need.

PascalMinder commented 7 months ago

Currently, only the two HTTP headers X-Forwarded-For and X-Real-IP are parsed to check for the country of origin. It looks like you only have the headers request_X-Forwarded-For. I don't know, but does Cloudflare add the request in front of the HTTP header name?

fdegraeve commented 7 months ago

Hello,

I make a deeper analysis.

Headers I deploy the traefik whoami image to check headers. Traefik add "request_" in log, but the header is good, it's X-Forwarded-For so no problem on header.

Problem With Cloudflare behind, X-Forwarded-For contains 2 IPs X-Forwarded-For: 92.159.32.169, 172.70.90.87 First the client IP, and second Cloudflare IP

I understand better with all logs, you check all IPs of the chain. Is not a problem when client and Cloudflare POP are in the same country, or 2 country allowed.

INFO: GeoBlock: 2023/11/24 16:59:26 geoblock@file: request allowed [92.159.32.169] for country [FR]
INFO: GeoBlock: 2023/11/24 16:59:26 geoblock@file: request allowed [172.70.85.120] for country [GB]

I have sometimes 403, because sometimes, Clouflare POP are in country [LV], on my blacklist. So I have

INFO: GeoBlock: 2023/11/24 17:09:18 geoblock@file: request allowed [92.159.32.169] for country [FR]
INFO: GeoBlock: 2023/11/24 17:09:18 geoblock@file: request denied [172.69.194.90] for country [LV]

I take a 403, but the client is on [FR] (allow country) because the request do client(FR) -> cloudflare (LV) -> server(FR).
I want check only the client, not the proxy.

They need an option to take only the first IP of X-Forwarded-For header. Depends if you want check all the path or just the client.

PascalMinder commented 7 months ago

Thanks for the detailed explanation. I will look into it.

fdegraeve commented 7 months ago

I change my strategy and add a blocklist in cloudflare too. It's better to block fast and not charge Traefik.

fdegraeve commented 7 months ago

If you want check only the client IP, I change the loop with this code in line 169,170

    for index, ipAddress := range reqIPAddr {
        if index == 0 {
        ...
        }
jerrywoo96 commented 2 months ago

Suggestion: how about specifying which header to use to get the client's real ip address? For example, if we put our server behind cloudflare, cloudflare will append the Cf-Connecting-Ip which contains the client's ip address to the request that can be read by the middleware. Therefore, we can specify which header contains the real client ip address to use for querying the country code.