HTTP 参数污染(HPP):服务器、代理服务器(Proxy)、WAF 与应用框架对重复的 query/body 键值(key)解析逻辑不一致。适用于过滤层与应用层对“哪个参数值优先生效”存在歧异的场景,可用来绕过安全防护、实现 SSRF 二次 URL 注入、滥用业务逻辑或混淆 CSRF Token。
SKILL: HTTP Parameter Pollution (HPP)
AI 载入指令:建立完整请求路径的模型:浏览器 → CDN/WAF → 反向代理 → 应用框架 → 业务程序代码。重复的键值(
a=1&a=2)在 HTTP 协议层面并非错误;每个节点(hop)可能各自选择取第一个值、取最后一个值、合并字符串(join)或转换为数组(array-ify)。当 WAF 与应用程序逻辑产生歧异,或是内部 HTTP Client 会重新组装 query string 时,请测试 HPP。路由说明:当同一个参数多次出现,或 WAF/后端技术栈不同时,请先使用 Section 1 的对照表测试首项/尾项/合并等解析假设,再设计 Section 3 的攻击场景链。
0. 快速开始
假设:安全检查读取的是其中一个参数值,而实际操作/业务逻辑读取的则是另一个参数值。
首波测试 Payload
id=1&id=2
id=1&id=1%20OR%201=1
url=https://legit.example&id=https://evil.example
amount=1&amount=9999
csrf=TOKEN_A&csrf=TOKEN_B
user=alice&user=admin
Body 变体(POST 请求重复测试)
application/x-www-form-urlencoded
id=1&id=2
multipart/form-data
------boundary
Content-Disposition: form-data; name="id"
1
------boundary
Content-Disposition: form-data; name="id"
2
快速测试方法
- 先使用基线
a=1&a=2识别前段技术栈(CDN/WAF)与源站(语言/框架)的指纹特性。 - 以两种顺序发送请求:
a=1&a=2与a=2&a=1(某些解析器对顺序极为敏感)。 - 若为 JSON:测试重复 key 以及 Content-Type 混淆(参阅 Section 2)。
1. 服务器行为对照表
常见默认行为 — 请务必自行确认;中间件(middleware)与自定义解析器可能会覆盖这些设置。
| 架构/技术栈 | 解析行为 | 示例:a=1&a=2 |
|---|---|---|
PHP / Apache ($_GET) |
取最后一个值 (Last occurrence) | a=2 |
| ASP.NET / IIS | 通常以逗号拼接 (Often comma-joined) | a=1,2 |
| JSP / Tomcat (servlet param) | 取第一个值 (First occurrence) | a=1 |
Python / Django (QueryDict) |
取最后一个值 (Last occurrence) | a=2 |
Python / Flask (request.args) |
取第一个值 (First occurrence) | a=1 |
Node.js / Express (req.query) |
转换为数组 (Array of values) | a=['1','2'](数据结构可能因解析器版本而异) |
| Perl / CGI | 取第一个值 (First occurrence) | a=1 |
| Ruby / Rack (Rack::Utils) | 取最后一个值 (Last occurrence) | a=2 |
Go net/http (ParseQuery) |
取第一个值 (First occurrence) | a=1 |
为何这很重要:运行于 IIS 上的 WAF 可能会解析成 1,2,而后端的 PHP 却只收到 2 — 若中间代理进行了正则化(normalization),也可能出现相反情况。
2. PAYLOAD 模式
2.1 基础重复 Key
GET /api?q=safe&q=evil HTTP/1.1
2.2 数组样式(PHP / 部分框架)
GET /api?id[]=1&id[]=2 HTTP/1.1
2.3 数组与标量混合
GET /api?item[]=a&item=b HTTP/1.1
2.4 编码后的 Ampersand (&)(解析器差异)
# 值内部的字面量 & 与新参数对 — 取决于解码器实现
param=value1%26other=value2
param=value1&other=value2
2.5 嵌套 / 括号 Key
GET /api?user[name]=a&user[role]=user&user[role]=admin HTTP/1.1
2.6 JSON 重复 Key
{"test":"user","test":"admin"}
许多解析器会保留最后一个 key;有些则保留第一个。JavaScript 的 JSON.parse 会保留最后一个重复的 key。
3. 攻击场景
3.1 HPP + 绕过 WAF
模式:WAF 检查第一个值;应用程序使用最后一个值。
id=1&id=1%20UNION%20SELECT%20...
亦可尝试:若 API 网关在合并不同来源时处理逻辑不同,可尝试在 JSON 字段中放入无害值,并在 query string 中放入重复参数。
3.2 HPP + SSRF
模式:验证器(Validator)读取的是安全的 URL;而实际发起请求的组件(Fetcher)读取的是内部/恶意的 URL。
url=https://allowed.cdn.example/&url=http://169.254.169.254/
请确认哪一个组件(第三方库 vs 应用程序本身)消费了哪一个参数位置。
3.3 HPP + CSRF
模式:重复发送 Anti-CSRF Token,使其中一份满足解析器 A,另一份满足解析器 B。
csrf=LEGIT&csrf=IGNORED_OR_ALT
仅用于拥有明确状态变更目标且获得合法授权的 CSRF 评估任务。
3.4 HPP + 业务逻辑(例如支付)
amount=1&amount=5000
quantity=1&quantity=-1
price=9.99&price=0.01
搭配竞态条件(Race Conditions)或服务器端舍入误差可造成更高影响;单独使用 HPP 通常需要跨层级的歧异解析才能生效。
4. 工具
| 工具 | 使用方式 |
|---|---|
| Burp Suite | Repeater:在原始 query/body 中注入重复 key;使用 Param Miner 或扩展功能寻找隐藏参数;对比响应以判断服务器偏好 first 或 last |
| OWASP ZAP | 使用 Manual Request Editor(手动请求编辑器);自动扫描可能无法深度 Fuzz HPP,建议以手动变体测试为主 |
| 自定义脚本 | 构建精确的原始 HTTP 请求(保留参数顺序)— 某些 HTTP Client 会自动格式化或去重重复参数 |
技巧:若你拥有测试环境的控制权,请在应用端记录原始(raw) query string;部分框架仅会在代码中暴露“胜出”的值,但日志中会保留完整字符串。
5. 决策树
+-------------------------+
| 重复的参数名称 |
| (发生在同一请求中) |
+------------+------------+
|
+------------------+------------------+
| |
+------v------+ +------v------+
| 仅单一应用 | | WAF / CDN / |
| 层级 | | 代理链 |
+------+------+ +------+------+
| |
+---------v---------+ +---------v---------+
| 查阅框架文档并测试 | | 绘制每个节点的行为: |
| a=1&a=2 与交换顺序 | | 取首/取尾/拼接/数组|
+---------+---------+ +---------+---------+
| |
+------------------+------------------+
|
+------v------+
| 选择攻击 |
| 模板 |
+------+------+
|
+-----------+-----------+-----------+-----------+
| | | | |
+----v----+ +----v----+ +----v----+ +----v----+ +----v----+
| WAF vs | | SSRF | | CSRF | | 逻辑 | | JSON |
| 应用层 | | 分离 | | Token | | 数值 | | 重复 key|
| 取值歧异| | URL | | 混淆 | | 字段 | | 解析器 |
+---------+ +---------+ +---------+ +---------+ +---------+
安全与范围说明:HPP 测试可能会改变服务器状态(如支付金额、账号设置)。请仅在获得明确授权的环境下执行,使用专用测试账号,并在发动高风险请求前先梳理并记录解析器的行为模式。






