◈ 渗透任务 data: URI 安全评估 任务中
你的身份 「暗影安全公司」渗透测试工程师 目标网站 EmbedView 内嵌预览服务 (embed.embedview.example.com) 委托方 EmbedView 允许用户提交 data: URI 并在 iframe 中预览 任务目标 利用 data: URI 在 iframe 中嵌入恶意脚本

◈ 教程:data: URI XSS

什么是 data: URI?

data: URI scheme(RFC 2397)允许在 URL 中直接嵌入小型数据资源,无需从外部服务器加载。其基本格式为:

data:[<mediatype>][;base64],<data>
核心概念:data: URI 可以指定任意 MIME 类型。当类型为 text/html 时,浏览器会将其作为完整的 HTML 文档解析和渲染,其中的 JavaScript 代码会正常执行。

基本语法

// 纯文本
data:text/plain,Hello World

// HTML 文档
data:text/html,<h1>Hello</h1>

// 带脚本的 HTML
data:text/html,<script>alert(1)</script>

// Base64 编码
data:text/html;base64,PHNjcmlwdD5hbGVydCgxKTwvc2NyaXB0Pg==

在 XSS 中的利用场景

data: URI XSS 通常出现在以下场景:

  • iframe src — 页面将用户输入作为 iframe 的 src
  • object/embed data — object 标签的 data 属性
  • window.open() — JavaScript 打开新窗口的 URL
  • location.href — 重定向到 data: URI
  • href 属性 — 链接目标为 data: URI

编码方式

方式 1:原始文本
data:text/html,<script>alert(1)</script>

直接嵌入 HTML,特殊字符需要保持原样(在 URL 中会被自动解码)。

方式 2:URL 编码
data:text/html,%3Cscript%3Ealert(1)%3C/script%3E

对 HTML 中的特殊字符进行 URL 编码。

方式 3:Base64 编码
data:text/html;base64,PHNjcmlwdD5hbGVydCgxKTwvc2NyaXB0Pg==

将整个 HTML 内容进行 Base64 编码,适合绕过简单的关键字过滤。

安全过滤的不足

许多开发者认为 htmlspecialchars() 就能阻止 XSS,但 data: URI 的特殊性在于:

  • 它是一个合法的 URL scheme,不会被 HTML 实体编码影响
  • 作为 iframe src 时,内容在独立的浏览上下文中渲染
  • 虽然同源策略限制了对父页面的直接访问,但仍可窃取 URL 参数、执行钓鱼等

浏览器差异

场景 Chrome Firefox Safari
iframe src="data:..." 允许 允许 允许
navigation to data: 允许 允许 限制
window.open("data:...") 允许 允许 限制
a href="data:..." 允许 允许 限制

◈ 练习:data: URI XSS

目标:页面允许你输入一个 URL,该 URL 会被设置为 iframe 的 src 属性。 服务端没有对 URL 的协议(scheme)做任何限制。利用 data: URI 在 iframe 中注入并执行脚本。
重置
iframe 渲染区:

上方输入一个 URL 后点击"加载",iframe 将在此处显示内容。

示例用法:
  • 正常 URL:https://example.com
  • data: URI(HTML):data:text/html,<h1>Hello</h1>
  • data: URI(Base64):data:text/html;base64,PGgxPkhlbGxvPC9oMT4=
◈ 查看漏洞源码 (PHP)
<?php $url = $_GET['url'] ?? ''; // 危险:直接将用户输入作为 iframe src,未做任何过滤 echo '<iframe src="' . $url . '" width="100%" height="200"></iframe>'; ?>
◈ 过滤状态:
  • URL 协议(scheme)检查 — 未过滤
  • data: URI 检测 — 未过滤
  • HTML 实体编码 — 仅用于输入框回显
  • iframe src 赋值 — 直接拼接用户输入