nginx作为反向代理服务器,站点几乎成了互联网基础设施的请求一部分。但很多人把它当成一面坚不可摧的伪造墙,却忘了它也可能是漏洞攻击链上最容易被忽视的一环。跨站点请求伪造(CSRF)在nginx层面爆发时,站点问题往往不是请求nginx本身有漏洞,而是伪造它默认的“转发一切”姿态,把后端应用的漏洞弱点放大了十倍。
举个实际例子。站点某电商平台架构是请求nginx前置,后面挂着一堆Java服务。伪造他们有个修改收货地址的漏洞接口,校验token的站点逻辑写在后端。攻击者构造了一个恶意页面,请求里面藏了个自动提交的伪造form表单,直接向那个接口发POST请求。nginx做了什么?它什么都没做,只是忠实地把请求转给了后端。后端如果没校验Referer或自定义头,这个请求就被当成合法操作处理了。受害者只要浏览器里还存着该平台的cookie,攻击就成功了。整个过程nginx像个沉默的帮凶。
关键问题在于,nginx的配置里通常只关注URL匹配和负载均衡,很少有人去想“这个请求该不该被转发”。CSRF的本质是浏览器会带着目标站点的cookie自动发起请求,nginx作为第一道关口,理论上完全有能力拦截掉那些来源可疑的跨站流量。但默认配置下,它对请求的来源、Content-Type、自定义header一概不闻不问。
有个冷门但实用的技巧——nginx可以强制校验请求头中的Sec-Fetch-Site字段。这是现代浏览器自动携带的安全信号,取值有cross-site、same-origin、none等。如果业务上不允许跨站调用,直接在nginx层加一行判断:
if ($http_sec_fetch_site !~* "^(same-origin|same-site|none)$") { return 403; }这能干掉绝大多数基于浏览器自动发起的CSRF攻击。老旧的浏览器或者用curl模拟的请求不带这个头,那就需要额外判断——但那种场景下攻击者多半已经能直接操控客户端了,CSRF反而没意义。另一个容易被忽略的点是nginx对请求方法的重写。有些后端接口明明只接受POST,但nginx配置里写了
error_page 405 = @fallback之类的规则,把GET请求也转给了后端。攻击者用标签发起GET请求,后端如果处理了,照样构成CSRF。检查一下你的nginx里有没有把405错误转成200的骚操作,那等于亲手给攻击者开了侧门。
别指望后端能扛住一切。很多Java框架的CSRF防护默认是关的,Spring Security要显式配置才生效。PHP项目更不用说了,一堆老代码连token都不带。nginx作为最前置的入口,加几行规则的成本远低于让所有后端业务方去改代码。我见过一个团队,把CSRF校验逻辑写进nginx的lua脚本里,统一检查请求来源和自定义token,上线后安全告警直接清零。
当然,nginx不是万能的。它无法防御基于JSON的CSRF攻击——那种用application/json内容类型发起的跨站请求,因为传统form表单无法构造这种类型,所以很多防护策略会放行。但攻击者可以用fetch API跨域发JSON,前提是目标站点允许CORS。这时候nginx的add_header Access-Control-Allow-Origin配置如果写得太宽松,比如直接返回
*,那就等于自己拆了护栏。检查下你的CORS配置,别让“允许所有来源”成为默认值。最后说个反直觉的事。有些人觉得给nginx加CSRF防护会影响性能,其实完全多虑了。nginx处理请求头匹配的速度是纳秒级的,比后端做一次session查询快几个数量级。真正拖慢响应的是那些在nginx层做了复杂正则匹配又没缓存规则的配置。与其担心性能,不如担心你的规则写得太绕,把自己人都绕晕了。
nginx的CSRF漏洞不是某个CVE编号能概括的,它更多是配置不当引发的系统性风险。与其等安全团队扫描报告,不如现在就打开nginx.conf,看看那些location块里有没有对请求来源做任何限制。大概率你会发现,自己暴露在跨站攻击下已经很久了。
顶: 5121踩: 73914






评论专区