最有效防御是前置拦截非必需XML请求:用location匹配.xml等后缀或map+if按Content-Type(application/xml/text/xml)返回403,严格限定SOAP等必要XML仅走专用upstream,并设client_max_body_size、限速及头部防护。

直接关闭不必要的 XML 解析转发,是 Nginx 层最有效、最前置的防御动作。Nginx 本身不解析 XML,但若配置为将 XML 类型请求原样透传给后端(如 Java/Spring 或 PHP 应用),而这些后端又未禁用外部实体或未做输入净化,风险就完全暴露。因此,关键不是“让 Nginx 解析 XML”,而是“不让可疑 XML 请求抵达后端”。
识别并拦截非必需的 XML 请求
多数现代 Web 接口已转向 JSON,XML 仅保留在特定旧系统、SOAP 服务或管理接口中。应先明确:哪些路径/接口真正需要接收 XML?其余一律拒绝。
- 用 location 块精准匹配 XML 流量,例如:
location ~* \.(xml|xsd|wsdl)$ { deny all; }—— 直接禁止静态 XML 文件访问 - 对 POST/PUT 请求按 Content-Type 过滤:
if ($content_type ~* "application/xml|text/xml") { return 403; }(注意:不推荐在 server 级大量使用 if,建议结合 map + location) - 更稳妥方式是用 map 预定义规则,再在 location 中引用:
map $content_type $block_xml { default 0; "~*application/xml" 1; "~*text/xml" 1; }<br>...<br>if ($block_xml) { return 403; }
限制 XML 流量只进指定后端服务
即使必须支持 XML,也应严格限定其作用域,避免泛化转发。
- 为 SOAP 或遗留系统单独配置 upstream 和 location,例如:
upstream soap_backend { server 10.0.1.5:8080; }<br>location /services/ { proxy_pass http://soap_backend; } - 在该 location 内启用强校验:
– 设置 client_max_body_size 512k(防 XML 炸弹)
– 添加 proxy_set_header X-Content-Type-Options "nosniff" 防 MIME 类型混淆
– 使用 limit_req 限速,防止高频试探 - 其他所有 location(如 /api/、/v1/)默认不处理 XML,可显式添加:
if ($content_type ~* "(application|text)/xml") { return 406 "XML not accepted"; }
剥离或重写危险 XML 头部与内容
某些场景下不能直接拒收 XML(如兼容性要求),则需在转发前干预内容结构,消除攻击面。
- 禁用 DTD 和外部实体声明:用 ngx_http_xml_module(需编译启用)或 Lua 模块实现内容扫描
xml_disallow_doctype yes;<br>xml_disable_external_entities on;
- 用 ngx_http_lua_module 在 access 阶段检查请求体(需开启
lua_need_request_body on;):
– 匹配等高危模式<br>– 发现即 <code>ngx.exit(400)并记录日志 - 对确需转发的 XML,可强制重写 Content-Type 为自定义类型(如
application/vnd.myapp-xml+safe),后端据此启用严格解析策略,与普通 XML 流量隔离
验证是否生效的简单方法
部署后务必验证规则是否真实拦截,而非仅配置无误。
- 用 curl 发送典型 XXE 载荷:
curl -H "Content-Type: application/xml" --data '<?xml version="1.0"?>]><x>&e;</x>' https://yoursite.com/api/test—— 应返回 403/406,而非 200 或 500 - 检查 access.log,确认被拦截请求带有明确状态码和匹配的 URI/headers
- 在后端应用日志中确认:该类请求未到达业务层(即没有解析器报错或文件读取日志)











