跨站脚本攻击XSS防御实践:网站老被黑?手把手教你防住XSS

跨站脚本攻击XSS防御实践:网站老被黑?手把手教你防住XSS

网络安全wl5net2026-11-09 9:36:11A+A-
约 3589 字 · 预计阅读 8 分钟

前两天半夜两点,运维群里突然炸锅,监控报警显示某核心业务页面的UV骤降,紧接着收到用户反馈说页面跳到了博彩网站。排查了一圈才发现,运营在后台富文本里配置的一段促销代码,不知什么时候被注入了恶意脚本。对于绝大多数做前端和运维的朋友来说,跨站脚本攻击XSS防御实践从来不是纸上谈兵的理论题,而是一场只要稍有疏忽就会直接导致用户Cookie被盗、网站权重被搜索引擎清空的现实保卫战。

跨站脚本攻击XSS防御实践:网站老被黑?手把手教你防住XSS

这篇文章不聊那些假大空的维基百科定义,结合我多年在前端架构和SEO巡检中的填坑经历,把防御这事掰开揉碎说透。


一、 先搞清楚:黑客到底怎么把代码塞进来的?

简单来说,XSS的本质就是:用户的输入,被你的系统未经审查地当成了可执行代码。

很多开发者以为XSS就是弹个 alert(1),无伤大雅。但实际上黑客拿到了执行JS的权限,就等于接管了用户的浏览器。常见的形式无非三种,防御策略也得对症下药:

类型 攻击场景 危险等级 典型防范思路
存储型 (Stored) 攻击代码存进数据库(如评论区、个人简介),所有人访问都会中招 极高(影响面大) 入库过滤 + 出库严格转义
反射型 (Reflected) 攻击代码藏在URL参数里,诱导用户点击(如搜索框、分页参数) 高(依赖社工) 参数校验 + 服务端上下文编码
DOM型 (DOM-based) 完全发生在前端,不经过后端(如读取 location.hash 后直接写入页面) 中高(不易被WAF识别) 杜绝危险DOM API,使用安全框架

二、 切实可行的防御手段:这四步必须做全

如果你指望写一个正则去过滤 <script> 标签,那我劝你趁早打住。黑客有一万种绕过方式,比如利用大小写、<img> 标签的 onerror 属性、甚至是伪协议。真正的防御是一套组合拳。

1. 上下文敏感的输出编码(最有效的第一道墙)

不要把转义当成“简单替换尖括号”。数据输出到HTML正文、属性值、JavaScript变量还是URL中,需要的编码规则完全不同:

  • 输出到HTML主体:把 &, <, >, ", ' 转义为实体字符。
  • 输出到JS变量:绝对不能只做HTML转义!一定要使用标准的JSON序列化,或者确保字符串经过Unicode转义。
  • 输出到属性(如href/src):必须先做URL白名单校验,谨防 javascript:alert(1) 伪协议。
// 危险示范(很多老项目还在用):
div.innerHTML = "<a href='" + userInput + "'>点击查看</a>"; 

// 正确做法:
const safeLink = document.createElement('a');
// 校验是否为合法 http/https 协议
if (/^https?:\/\//i.test(userInput)) {
    safeLink.href = userInput;
    safeLink.textContent = "点击查看";
    div.appendChild(safeLink);
}

2. 富文本场景的“放行”方案

做内容网站、论坛免不了要让用户发富文本,全转义了排版就没了。这种情况下坚决不要手写清洗逻辑,直接引入成熟的开源库,比如前端的 DOMPurify 或后端的 sanitize-html。

// 使用 DOMPurify 清洗不可信的富文本内容
import DOMPurify from 'dompurify';

const dirtyHtml = `<p>欢迎阅读!<img src="x" onerror="alert('xss')"></p>`;
const cleanHtml = DOMPurify.sanitize(dirtyHtml);

// 渲染结果只会保留安全的 <p>欢迎阅读!<img src="x"></p>,onerror属性被直接剥离
document.getElementById('content').innerHTML = cleanHtml;

3. 运维必设:把 Cookie 的路堵死

黑客搞XSS,80%的目标是盗取用户的身份凭证(SessionID/Token)。只要拿不到这些凭证,攻击的破坏力就会大打折扣。

  • 在生成身份凭据的Cookie时,务必加上 HttpOnly 标记。这行配置会告诉浏览器:任何通过 document.cookie 的JS脚本都无权读取此值。
  • 顺便加上 Secure(仅HTTPS传输)和 SameSite=Lax/Strict(防CSRF协同攻击)。

4. 终极兜底方案:配置内容安全策略(CSP)

这是现代浏览器提供的最强防御网。你哪怕代码写漏了,只要CSP配置得当,黑客注入的脚本根本执行不起来。

在你的Nginx或者服务返回头里加上这行(根据项目实际情况调整):

# 严禁内联脚本执行,只允许加载本域及可信CDN的资源
Content-Security-Policy: default-src 'self'; script-src 'self' https://trustedscripts.example.com; object-src 'none';

一旦黑客试图注入一段内联 <script> 或者从未经认证的第三方服务器拉取木马JS,浏览器会直接掐断请求并在控制台报错。


三、 别踩框架的坑:用了Vue/React就百分之百安全?

现代前端框架确实在默认情况下对模板渲染做了转义,但这并不代表你高枕无忧了。日常Code Review中,这几个地方最容易爆雷:

  1. v-html 与 dangerouslySetInnerHTML:这是框架为了灵活性开的后门,也是线上事故的高发区。只要用了它们,就必须配合 DOMPurify 清洗。
  2. 动态执行代码:代码里出现 eval(), setTimeout("动态字符串", 1000), new Function() 等逻辑,任何传给它们的外部参数都极度危险。
  3. Markdown解析库:很多博客系统为了SEO会服务端渲染Markdown,有些解析器默认允许原样输出HTML,千万记得在解析选项里关闭HTML标签或者走清洗逻辑。

四、 从SEO和运维角度看:为什么搞好XSS防御能救命?

很多搞SEO的人只盯着TDK、外链和收录,完全忽视了安全。但现实情况是:XSS往往是恶意跳转、黑产外链的元凶。

黑客经常利用存储型XSS或者富文本漏洞,在你的正常文章里注入暗链(例如 font-size:0、负边距隐藏链接)。用户看不见,但百度和谷歌的爬虫看得清清楚楚。 更恶劣的会判断 User-Agent,如果是搜索引擎的Spider或者普通用户,就直接302重定向到垃圾站。结果往往是:你辛辛苦苦维护了大半年的网站权重,在一次漏洞利用后,几天内就被搜索引擎判定为被黑站点,直接拔毛降权,再想申诉恢复需要花费数倍的精力。


运维安全自查清单

最后给大家梳理一个可以直接上手的排查自检流程:

  1. 核心Cookie全量审查:登录态、用户敏感标识Cookie是否100%设置了 HttpOnly。
  2. 富文本与第三方库:代码库全局搜索 innerHTML, v-html, dangerouslySetInnerHTML,确认是否全部挂载了清洗过滤器。
  3. HTTP安全响应头:检查线上环境的 Content-Security-Policy 与 X-Content-Type-Options: nosniff 是否生效。
  4. WAF规则更新:云厂商的Web应用防火墙是否有拦截常见跨站注入特征的规则集。

安全防护没有银弹,它是一层层堆砌出来的壁垒。把输出转义当习惯,把清洗库当标配,再给运维配置套上CSP和HttpOnly,你才能安安稳稳地睡个好觉。

点击这里复制本文地址 以上内容由未来技术网整理呈现,请务必在转载分享时注明本文地址!如对内容有疑问,请联系我们,谢谢!

网站地图 robots.txt 网站死链 关于本站 工信部备案号浙ICP备2026012592号-2 浙公网安备33102402000669号