当前位置:首页 > 探索 > 脚本注入 正文

脚本注入

时间:2026-10-17 05:06:55 来源:力不从心网

去年十月,脚本注入一个做电商的脚本注入朋友发来求助:网站首页突然被插了一段 ``,用户点任何链接都会跳转到博彩页面。脚本注入他查了三天日志,脚本注入没找到入口。脚本注入最后发现漏洞藏在一个两年前上线的脚本注入富文本评论组件里——用户提交评论时,前端做了过滤,脚本注入后端直接入库,脚本注入渲染时 innerHTML 一把梭。脚本注入攻击者提交了一条含 `` 的脚本注入评论,就这么简单。脚本注入

脚本注入的脚本注入核心逻辑只有一句话:让浏览器把攻击者写的数据当成代码执行。听起来低级,脚本注入但它常年占据 OWASP Top 10,脚本注入原因不复杂——数据和代码的脚本注入边界,在很多开发者脑子里是模糊的。

三种最常见的入口

反射型最直白。搜索框输入 ``,服务端把关键词原样拼进 HTML 返回,浏览器一解析就执行了。这类漏洞在早期 Web 里遍地都是,现在少了很多,但没绝迹。我去年在一个政务网站的 404 页面里还见过——URL 路径直接输出到页面标题里,连转义都没有。

存储型更麻烦。数据进了数据库,每次有人访问就触发一次。留言板、用户昵称、商品评价、日志展示面板,都是重灾区。上面那个电商案例就是存储型。它的杀伤力在于不需要诱导点击,页面自己就中招。

DOM 型容易被忽略,因为服务端日志里什么都看不到。漏洞全在前端 JS 里:location.hash 取值后塞进 innerHTML,或者 eval() 了一段 URL 参数。服务端返回的 HTML 干干净净,问题出在浏览器端运行时。用 Burp 抓包看不出异常,得翻源码。

防御不是加个过滤器就完事

很多人第一反应是“把 <script> 过滤掉”。这思路本身就错了。攻击载荷根本不需要 script 标签——<img onerror>、<svg onload>、<body onpageshow>,甚至 javascript: 伪协议,绕过方式层出不穷。黑名单永远追不上变体。

正确的做法是上下文感知的输出编码。同一个字符串,放在 HTML 标签之间、属性值里、URL 里、JS 变量里,编码规则完全不同。React 和 Vue 默认做了转义,但 dangerouslySetInnerHTML 和 v-html 一开,防护就失效了。我见过一个团队用 Vue,所有用户内容都走 v-html 渲染,理由是“要支持富文本”。后来他们上了 DOMPurify 做白名单清洗,才算堵住。

CSP 是第二道防线。设置 Content-Security-Policy: script-src 'self',即使注入成功,内联脚本也执行不了。但它配置起来坑不少,unsafe-inline 一加就形同虚设,很多老项目因为历史代码依赖内联事件,根本推不动。所以 CSP 是兜底,不是替代方案。

还有个容易漏的点:HttpOnly Cookie。脚本注入最常见的利用方式是偷 session,如果关键 Cookie 标了 HttpOnly,JS 读不到,攻击收益直接砍半。这个配置成本极低,但我在渗透测试里发现至少四成站点没做。

一个真实的教训

2021 年某知名论坛被拖库,起因是一个 Markdown 编辑器。它允许用户嵌入 HTML,前端用正则过滤了 <script>,但没管 <iframe>。攻击者嵌入了一个指向自己域名的 iframe,里面放钓鱼表单,骗到了管理员的登录凭证。整个链路里没有一行传统意义上的“脚本注入代码”,但本质完全一样——用户输入被当成了页面结构的一部分。

这行的老手常说一句话:XSS 不是漏洞,是症状。真正的问题在于开发者对“数据”和“代码”的边界缺乏敬畏。框架帮你转义了,你就以为万事大吉;一旦有个口子需要绕过去,手一抖就开了后门。

修 XSS 没有银弹。输出编码、CSP、HttpOnly、输入校验,每层都得做,每层都不完美。但少做一层,攻击者的成本就降一个数量级。安全这件事,从来都是抬高门槛,不是砌一堵密不透风的墙。

推荐内容