chaitin / SafeLine

A web security gateway, serve as a reverse proxy to protect your websites from attacks and exploits.
https://waf.chaitin.com
GNU General Public License v3.0
10.87k stars 650 forks source link

[建议] 自定义规则支持判断某个请求头是否存在 #936

Closed Saobby closed 2 weeks ago

Saobby commented 2 weeks ago

背景与遇到的问题

我的雷池部署在客户端和后端服务之间,我把雷池的代理设置为从网络连接中获取客户端IP,我发现如果客户端请求的请求头中已经有了X-Forwarded-For字段,不论取值是什么,雷池都会在后面加上, 真实IP然后把它发送给上游服务器。

虽然真实IP还是在请求头里但是前面多了一段客户端发送的内容,虽然后段可以把客户端发送的那一段去掉,但是由于部署的服务众多,一个个改后端很麻烦,又因为雷池后面直接就是客户端了所以请求头中原有的X-Forwarded-For一定是假的,我就想在防火墙直接拦截所有包含X-Forwarded-For字段的请求。

我尝试了添加一个黑名单规则,用正则表达式.*匹配,如果X-Forwarded-For的值不为空他确实被拦截了,但是如果有X-Forwarded-For字段但是值为空那请求还是能够正常通过,后端收到的X-Forwarded-For就是, 真实IP,还是会多一个多余的逗号空格,我也没有找到能把空值一并拦截但不拦截正常不含X-Forwarded-For字段的请求的方法。

建议的解决方案

希望可以给自定义规则添加一个检测指定请求头是否存在的选项,或者在用户选择“从网络连接中获取客户端IP”时就自动舍弃客户端发来X-Forwarded-For字段。

Lorna0 commented 2 weeks ago

“检测某个请求头是否存在” 本身合理,放着收集下社区意见。

不过值得一提的是,源背景问题其实不太适合这样处理。即使雷池在最外层,正常用户也是有可能有 XFF 的。比如用户可能嫌本地区网速慢,挂了一个代理。这并不一定合理,但是用户也并不存在恶意。

实际推荐的做法是:1. 最外层代理设备重写 xff,或者将客户端 IP 放在一个自定义的 header 中(雷池可以通过自定义 nginx conf 来实现) 2. 其他代理设备以及网站不要直接取 XFF 最左 IP,而是从右往左取排除了内部 IP 之外的 IP,或者取前面说的自定义 header(也是雷池的做法)

实际我们遇到需要 “检测某个请求头是否存在” 的一般是业务上的特殊 header,这个 issue 会开放着收集意见。

Lorna0 commented 2 weeks ago

测试了一下,可以通过这样的条件来满足: image

唯一需要注意的是,若这个字段不存在或者字段名的内容为空,则该条件的判断结果都是 false。这是为了避免大范围误拦所设计的,因为这种情况比较容易配错。上面的规则配置效果如图, 403 表示命中拦截了,200 表示没有命中放行了:

image

Lorna0 commented 2 weeks ago

考虑到上面这个方法的例外情况比较罕见(一定要匹配 “字段名存在但内容为空” 的),所以暂时没计划支持。有需要可以再提个 issue 收集社区意见,反馈热烈的话会重新考虑。