关于X-Forwarded-For被伪造情况下获取真实ip的处理
2021-12-31 09:30:0 Author: mp.weixin.qq.com(查看原文) 阅读量:26 收藏

原文链接 :

https://zhuanlan.zhihu.com/p/134618410

背景

在风控场景下,有很多基于客户端ip的风控规则。通常通过http协议头中的X-Forwarded-For来获取ip,但该字段很容易被伪造,这种情况下该如何处理?

概念

X-Forwarded-For X-Forwarded-For 是一个扩展头。HTTP/1.1(RFC 2616)协议并没有对它的定义,它最开始是由 Squid 这个缓存代理软件引入,用来表示 HTTP 请求端真实 IP,现在已经成为事实上的标准,被各大 HTTP 代理、负载均衡等转发服务广泛使用,并被写入 RFC 7239(Forwarded HTTP Extension)标准之中.

$remote_addr
是nginx与客户端进行TCP连接过程中,获得的客户端真实地址. Remote Address 无法伪造,因为建立 TCP 连接需要三次握手,如果伪造了源 IP,无法建立 TCP 连接,更不会有后面的 HTTP 请求

$X-Real-IP
是一个自定义头。X-Real-Ip 通常被 HTTP 代理用来表示与它产生 TCP 连接的设备 IP,这个设备可能是其他代理,也可能是真正的请求端。需要注意的是,X-Real-Ip 目前并不属于任何标准,代理和 Web 应用之间可以约定用任何自定义头来传递这个信息

分析

网络请求通常是浏览器(或其他客户端)发出请求,通过层层网络设备的转发,最终到达服务端。那么每一个环节收到请求中的remote_addr必定是上游环节的真实IP,这个无法伪造。那从全链路来看,如果需要最终请求的来源,则通过X-Forwarded-For来进行追踪,每一环节的ip(remote_addr)都添加到X-Forwarded-For字段之后,这样X-Forwarded-For就能串联全链路了。

X-Forwarded-For: client_ip, proxy1_ip, proxy2_ip

以Nginx为例,添加X-Forwarded-For的配置方式为:

 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

如果用户在请求时候伪造的话,那么会出现上面案例的client1前面,出现伪造的ip:

X-Forwarded-For: 伪造ip1, 伪造ip2, client_ip, proxy1_ip, proxy2_ip

这样的话,需要取真实的client_ip,则需要取proxy1_ip前一个ip值;

如果想要过滤掉或覆盖伪造的ip的话,则需要第一层代理(proxy1)用remote_addr来覆盖X-Forwarded-For:

proxy_set_header X-Forwarded-For $remote_addr;

验证

准备Mock服务

from flask import Flaskfrom flask import request
app = Flask(__name__)
@app.route('/HelloWorld')def hello_world(): print request.headers return "Hello World!"
if __name__ == "__main__": app.run

准备Nginx代理

#user  nobody;worker_processes  1;
events { worker_connections 1024;}

http { include mime.types; default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"';
access_log logs/access.log main;
sendfile on; #tcp_nopush on;
#keepalive_timeout 0; keepalive_timeout 65;
#gzip on;
proxy_set_header Host $host; proxy_set_header Cookie $http_cookie; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
server { listen 80; server_name localhost;
#charset koi8-r;
#access_log logs/host.access.log main;
location / { root html; index index.html index.htm; proxy_pass http://localhost:5000/; }
#error_page 404 /404.html;
# redirect server error pages to the static page /50x.html # error_page 500 502 503 504 /50x.html; location = /50x.html { root html; } }

PostMan伪造x-forwarded-for发起请求

Nginx打印日志,可以看到前面打印的是$remote_addr真实IP,后面打印的是X-Forwarded-For伪造IP

Mock服务日志,可以看到真实地址已经被Nginx拼到X-Forwarded-For后面了


侵权请私聊公众号删文



文章来源: http://mp.weixin.qq.com/s?__biz=MzAxMjE3ODU3MQ==&mid=2650530909&idx=2&sn=e5ad6075bb6fc90f947e99a673be01db&chksm=83ba81b9b4cd08af947f42aad37caecb2cd1f93d9dcde13f24c3ded3a93b9b3042c214d8298e#rd
如有侵权请联系:admin#unsafe.sh