Flask中request.remote_addr总是127.0.0.1或代理IP,因其获取的是直接连接的上一跳地址;真实IP需从X-Forwarded-For等可信头中按代理链过滤提取,且必须配置可信代理列表或ProxyFix参数,否则存在伪造风险。

Flask里request.remote_addr为什么总是127.0.0.1或代理IP
因为你的Flask应用大概率跑在Nginx、Gunicorn或云服务商(如AWS ALB、Cloudflare)后面,request.remote_addr拿到的是**直接连接的上一跳地址**,不是用户真实出口IP。比如Nginx反向代理时,Flask看到的就是Nginx本机IP;K8s Ingress后则是Ingress Controller的IP。
真实IP通常藏在HTTP头里,最常见的是X-Forwarded-For,但这个头可被客户端伪造,不能直接信任。
- 必须配合可信代理列表使用,否则有IP伪造风险
- 不同代理添加
X-Forwarded-For的方式略有差异:有些追加,有些覆盖,有些还带端口(如192.168.1.100:12345) - Cloudflare会用
Cf-Connecting-Ip,AWS ALB用X-Forwarded-For但只保证最后一段可靠
如何安全地从X-Forwarded-For提取真实IP
核心逻辑是:从X-Forwarded-For头取最右边“可信代理链之外”的第一个IP。你需要明确知道哪些IP/网段是你的入口代理(比如Nginx服务器的内网IP),然后从右往左数,跳过这些可信地址,取第一个非可信IP。
示例代码(不依赖第三方库):
def get_real_ip(request):
# 你实际的可信代理IP列表(务必按真实环境填写)
trusted_proxies = {'127.0.0.1', '10.0.0.0/8', '172.16.0.0/12', '192.168.0.0/16'}
<pre class="brush:php;toolbar:false;">ip = request.remote_addr
if not request.headers.get('X-Forwarded-For'):
return ip
# 解析X-Forwarded-For,取最右非空项
forwarded_ips = [ip.strip() for ip in request.headers['X-Forwarded-For'].split(',') if ip.strip()]
if not forwarded_ips:
return ip
# 从右往左找第一个不在trusted_proxies里的IP
for candidate in reversed(forwarded_ips):
# 去掉可能的端口(如 192.168.1.100:5000 → 192.168.1.100)
clean_ip = candidate.split(':')[0]
if not any(ip_in_network(clean_ip, net) for net in trusted_proxies):
return clean_ip
return ip # 全部都在可信列表里,fallback到remote_addr
注意:ip_in_network需自行实现(可用ipaddress模块),或直接用字符串匹配简化版(仅适用于固定IP,不推荐生产)。
用Werkzeug的ProxyFix中间件更省事但要小心配置
Flask底层Werkzeug提供了ProxyFix,能自动处理X-Forwarded-For和X-Forwarded-Proto等头。但它默认只信任127.0.0.1,**不配就等于没用**。
- 必须显式设置
x_for=1(表示X-Forwarded-For可信跳数),或用trusted_hosts指定代理主机名 - 如果代理链有Nginx + Cloudflare,
x_for应设为2(Cloudflare加Nginx各1跳) - 启用后,
request.remote_addr会自动变成真实IP,但request.headers.get('X-Forwarded-For')仍存在,别混淆
典型用法:
from werkzeug.middleware.proxy_fix import ProxyFix
app.wsgi_app = ProxyFix(
app.wsgi_app,
x_for=2, # 信任X-Forwarded-For中最后2个IP
x_proto=1,
x_host=1,
x_port=1,
x_prefix=1
)
Cloudflare、AWS ALB等托管服务的特殊处理
它们不完全遵循标准X-Forwarded-For行为,或额外提供更可靠的头:
- Cloudflare:优先读
request.headers.get('Cf-Connecting-Ip'),它不可伪造且总为真实IP(需在Cloudflare面板开启“True Client IP”) - AWS ALB:
X-Forwarded-For最右边IP是真实客户端IP,但ALB本身不校验来源,所以仍需限制ALB安全组只允许来自CloudFront或公司出口IP访问 - Vercel / Netlify:用
X-Real-IP或X-Forwarded-For最右段,文档明确说明其可靠性
建议写一个兜底函数,按顺序检查这些头:
def get_client_ip(request):
# 优先级:Cloudflare > ALB/Vercel > X-Forwarded-For(带可信代理过滤) > remote_addr
ip = (request.headers.get('Cf-Connecting-Ip') or
request.headers.get('X-Real-IP') or
request.headers.get('X-Forwarded-For', '').split(',')[-1].strip().split(':')[0])
return ip if ip and ip != '127.0.0.1' else request.remote_addr
真实IP获取的关键不在“怎么取”,而在“信谁”。漏掉一个代理IP段,或把公网IP误标为可信,都会导致IP伪造漏洞。别图省事全信X-Forwarded-For,也别把ProxyFix的默认值当万能解。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











