Asp.Net Core: 在Cloudflare代理下的Linux服务器中处理ForwardedHeader并获取源IP
配置Asp.Net Core程序使用反向代理
一般来讲, 部署在 Linux 下的 Asp.Net Core 应用都不会将Kestrel
服务器的监听端口直接暴露在生产环境中, 而是经过一层Web服务器作反向代理, 这个服务器可以是caddy
, nginx
或apache
等.
但是, 经过反向代理之后, 从Request
上下文中获得的源IP地址与源传输协议(HTTP
/HTTPS
)一般都会为127.0.0.1
(或反向代理服务器的地址)与http
, 这会导致基于IP的请求熔断器无法正常工作, 如果启用了HttpsRedirection
, 还会导致进入无限重定向循环中.
为了解决这个问题, 反向代理服务器一般会通过X-Forwarded-For
与X-Forwarded-Proto
两个Http头来传递实际的请求IP与请求协议, 因此只要配置服务器使用这个请求头中的数据替换原始的源IP及协议即可.
对于只有一层反向代理服务器的情况来说, 解决这个问题的方式非常简单.
- 在运行目标 Asp.Net Core 应用的环境中配置环境变量
ASPNETCORE_FORWARDEDHEADERS_ENABLED
为true
即可. 这一般可以通过修改systemd
服务配置等方法实现.
如果配置了这个环境变量, Asp.Net Core应用会无条件信任来自所有源的请求中的X-Forwarded-For
与X-Forwarded-Proto
头. 这有可能导致X-Forwarded-For
头欺诈的情况发生, 从而导致IP熔断器失效. 因此必须保证Kerstrel
服务器的监听端口不可被不受信任的来源访问, 建议通过配置防火墙等方式实现, 或改用下面的方法.
- 可以在程序初始化配置中添加与
ForwardedHeaders
中间件相关的配置代码实现:
1 | // add at ConfigureServices() if you are using classic template |
这段配置代码默认只会信任localhost
, 如需信任其它服务器来源, 可通过修改KnownProxies
实现.
配合CloudFlare及其它反向代理/CDN服务器使用
配置Asp.Net Core服务器
配置其它外部CDN后, Http请求会经过两层反代才会到达Kestrel
服务器. 但是默认配置下, ForwardedHeaders
中间件最对只会处理一种反向代理的情况. 如果有多层反向代理, 它会将最后一层反代服务器所设定的值作为源IP与源协议值.
要改变这一行为, 只需要更改ForwardLimit
的值即可(默认为1
)
下面的配置代码可以从配置文件读入ForwardLimit
值:
1 | builder.Services.Configure<ForwardedHeadersOptions>(options => |
然后在appsettings.json
中添加…
1 | { |
配置Caddy服务器
信任外部反向代理IP
为了防止X-Forwarded-For
头欺诈, Caddy服务器默认不会信任外部请求所提供的X-Forwarded-For
与X-Forwarded-Proto
请求头. 因此需要为Caddy配置Cloudflare的信任IP:
Cloudflare会通过文档与api公布它们的CDN IP地址范围, 将这部分地址加入到Caddyfile的trust_proxy
中即可.
1 | # ... |
此处的Cloudflare IP地址仅作为配置示例且可能已经过时, 请以从Cloudflare中获取的最新地址为准.
Cloudflare的IP地址会不定时更新, 如果你不想手动维护这个信任地址列表的话, 可以参考下面的方法
自动维护信任的Cloudflare IP列表
这里我使用一个python脚本自动维护IP列表. 创建/etc/caddy/update_cloudflare.py
:
1 | #!/usr/bin/python |
完成后添加运行权限sudo chmod +x update_cloudflare.py
, 然后以sudo权限执行一次
然后修改/etc/caddy/Caddyfile
:
1 | reverse_proxy 127.0.0.1:5000 { |
然后配置计划任务, 以sudo权限运行crontab:
1 | sudo crontab -e |
添加下面这一行即可.(下面这行代码会在每天0点从api更新cloudflare ips)
1 | 0 0 * * * cd /etc/caddy && ./update_cloudflare.py |
配置Cloudflare
此节摘自Authelia docs
当传入请求中已经存在X-Forwarded-For
头时, cloudflare会直接在原有的请求头中追加一个IP. 这意味着用户可能可以通过伪造X-Forwarded-For
头来伪造IP, 即X-Forwarded-For
欺诈. 因此, 强烈建议在Cloudflare中配置删除X-Forwarded-For
头的操作.
方法:
- 进入Cloudflare控制台, 选择
Rules
- 选择
Transform Rules
- 选择
Create transform rules
- 选择
Modify Request Header
- 将
Rule name
更改为Remove X-Forwarded-For Header
或其它名字 - 将
Field
设置为X-Forwarded-For
- 将
Operator
设置为does not equal
- 将
Value
留空 - 将
Then
操作设置为Remove
- 将
Header name
设置为X-Forwarded-For
- 保存
Save