关于 http-parameter-pollution
面向 Web 安全测试人员的 HTTP 参数污染(HPP)测试指南,重点分析请求处理各层如何解析重复参数,并提供验证解析差异的方法。
主要功能
- 01重复参数行为对照表
- 02查询、表单与 JSON 测试模式
- 03WAF 绕过与 SSRF 场景
- 04CSRF 与业务逻辑场景
- 05Burp Suite 和 OWASP ZAP 测试建议
- 06原始请求顺序检查
适用场景
- 01检查请求各层如何处理重复键
- 02测试 WAF 与后端的解析差异
- 03评估重复参数导致的 SSRF 行为
- 04检查支付或账户流程中的参数歧义
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ yaklang/ hack-skills --skill http-parameter-pollution安装后在 Claude Code 中输入/http-parameter-pollution确认已加载。
详细介绍
技能:HTTP 参数污染(HPP)
AI 加载说明:建模完整请求路径:浏览器 → CDN/WAF → 反向代理 → 应用框架 → 业务代码。重复键(
a=1&a=2)在 HTTP 层并不算错误;每一跳都可能取第一个值、最后一个值、合并值或转成数组。当 WAF 与应用的处理方式不一致,或内部 HTTP 客户端会重建查询字符串时,应测试 HPP。路由说明:当同一参数出现多次,或 WAF 与后端技术栈不同时,使用第 1 节的矩阵测试取第一个值、取最后一个值和合并值的假设,然后设计第 3 节中的场景链。
0. 快速入门
假设:安全检查读取参数的一个值,而操作读取另一个值。
首轮测试载荷
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
请求体变体(对 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:测试重复键和 Content-Type 混淆(参见第 2 节)。
1. 服务端行为矩阵
典型默认行为——务必确认;中间件和自定义解析器可能会覆盖这些行为。
| 技术 | 行为 | 示例:a=1&a=2 |
|---|---|---|
PHP / Apache($_GET) | 取最后一个值 | a=2 |
| ASP.NET / IIS | 通常合并为逗号分隔的值(全部) | a=1,2 |
| JSP / Tomcat(servlet 参数) | 取第一个值 | a=1 |
Python / Django(QueryDict) | 取最后一个值 | a=2 |
Python / Flask(request.args) | 取第一个值 | a=1 |
Node.js / Express(req.query) | 值数组 | a=['1','2'](形式可能因解析器版本而异) |
| Perl / CGI | 取第一个值 | a=1 |
| Ruby / Rack(Rack::Utils) | 取最后一个值 | a=2 |
Go net/http(ParseQuery) | 取第一个值 | a=1 |
重要原因:IIS 上的 WAF 可能看到 1,2,而 PHP 后端只接收到 2——若代理进行了规范化,情况也可能相反。
2. 载荷模式
2.1 基本重复键
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 编码后的与号(解析器差异)
# Literal & inside a value vs new pair — depends on decoder
param=value1%26other=value2
param=value1&other=value2
2.5 嵌套键 / 方括号键
GET /api?user[name]=a&user[role]=user&user[role]=admin HTTP/1.1
2.6 JSON 重复键
{"test":"user","test":"admin"}
许多解析器会保留最后一个键;有些会保留第一个。JavaScript JSON.parse 会保留最后一个重复键。
3. 攻击场景
3.1 HPP + WAF 绕过
模式:WAF 检查第一个值;应用使用最后一个值。
id=1&id=1%20UNION%20SELECT%20...
还可以尝试:如果网关合并不同来源的方式不同,则在查询字符串中重复添加 JSON 字段里的无害值。
3.2 HPP + SSRF
模式:验证器读取安全 URL;抓取器读取内部/恶意 URL。
url=https://allowed.cdn.example/&url=http://169.254.169.254/
确认哪个组件(库还是应用)会读取哪个值。
3.3 HPP + CSRF
模式:重复添加防 CSRF 令牌,使其中一个副本满足解析器 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
与竞态条件或服务端舍入结合可提高影响;单独使用 HPP 通常需要不同层以不同方式解析参数。
4. 工具
| 工具 | 用法 |
|---|---|
| Burp Suite | Repeater:在原始查询字符串/请求体中添加重复键;使用 Param Miner / 扩展查找隐藏参数;比较对取第一个值与取最后一个值的不同解析方式的响应 |
| OWASP ZAP | 手动请求编辑器;自动扫描可能不会深入模糊测试 HPP——建议使用手动变体 |
| 自定义脚本 | 构造精确的原始 HTTP 请求(保留顺序)——有些客户端会规范化重复项 |
提示:如果你控制着测试实验室,可在应用中记录原始查询字符串;有些框架只会提供最终生效的值,而日志会显示完整字符串。
5. 决策树
+-------------------------+
| Duplicate param name |
| same request |
+------------+------------+
|
+------------------+------------------+
| |
+------v------+ +------v------+
| Single app | | WAF / CDN / |
| layer only | | proxy chain |
+------+------+ +------+------+
| |
+---------v---------+ +---------v---------+
| Read framework | | Map each hop: |
| docs + test | | first/last/join/ |
| a=1&a=2 vs swap | | array |
+---------+---------+ +---------+---------+
| |
+------------------+------------------+
|
+------v------+
| Pick attack |
| template |
+------+------+
|
+-----------+-----------+-----------+-----------+
| | | | |
+----v----+ +----v----+ +----v----+ +----v----+ +----v----+
| WAF vs | | SSRF | | CSRF | | Logic | | JSON |
| app | | split | | token | | numeric | | dup key |
| value | | URL | | confuse | | fields | | parsers |
+---------+ +---------+ +---------+ +---------+ +---------+
安全与范围:HPP 测试可能会更改服务端状态(付款、账户设置)。仅在获得明确授权的情况下运行,使用范围受限的账户,并在发送高影响请求前记录解析器的行为。