游客发表
跨站脚本攻击(XSS)能得手,根本原因就一个:服务器把用户输入的利用漏洞数据当成代码执行了。更准确地说,利用漏洞是利用漏洞浏览器无法区分“这段内容到底是数据还是指令”——当网页把未经充分处理的内容直接塞进HTML里,浏览器就会老老实实按照标签或脚本去解析。利用漏洞这不是利用漏洞什么高深漏洞,而是利用漏洞最基础的“信任边界”被打破。
我最早接触XSS是利用漏洞在一个二手论坛上。有人发帖标题写的利用漏洞是 <script>alert('xss')</script>,结果整个帖子列表页弹了十几次警告框。利用漏洞当时论坛程序把标题直接拼进了HTML,利用漏洞连尖括号都没转义。利用漏洞这背后就是利用漏洞典型的“输出编码缺失”——服务器信任了用户提交的原始字符串,浏览器又信任了服务器返回的利用漏洞HTML。两边都以为对方会做好过滤,利用漏洞结果谁都没做。
具体分三种情况。反射型XSS最常见,比如搜索框输入 <img src=x onerror=alert(1)>,服务器把搜索词直接显示在结果页上。存储型更麻烦,像留言板、用户昵称、商品评论,恶意脚本存进数据库,每个访问者都会中招。DOM型则完全发生在浏览器端,比如 location.hash 被 innerHTML 直接使用,服务器甚至没参与。
<script> 标签内,照样能闭合字符串执行代码。 很多人以为过滤 <script> 就安全了。我见过一个后台系统,把 script 关键字替换成空字符串。攻击者写 <scrscriptipt>,过滤一次后变成 <script>。这种“黑名单”思路从根上就错了。正确的做法是输出编码:在HTML实体中,< 变成 <,> 变成 >,& 变成 &。在JavaScript字符串里,还得处理引号和换行。
另一个容易被忽略的细节:浏览器解析HTML时,属性值不加引号也能工作。比如 <img src=用户输入>,如果用户输入 x onerror=alert(1),就变成了 <img src=x onerror=alert(1)>。所以给属性值加引号并转义引号,是基本要求。但很多模板引擎默认不转义,或者开发者手动拼接字符串时忘了这回事。
现代前端框架(React、Vue、Angular)默认会对插值进行转义,这减少了很多低级XSS。但危险依然存在:dangerouslySetInnerHTML、v-html、bypassSecurityTrustHtml——这些API名字就在提醒你“这里不安全”。我见过一个Vue项目,用 v-html 渲染用户提交的Markdown,结果Markdown里的 <img onerror> 直接执行。框架帮你转义了,但你自己开了后门。
CSP(内容安全策略)能缓解XSS,但它不是修复漏洞的手段。如果输出编码没做好,CSP只是让攻击者换个方式——比如利用白名单里的CDN加载恶意脚本。我调试过一个站点,CSP允许 script-src 'self',但有个JSONP端点返回用户可控的回调函数名,照样能执行任意代码。所以根子还在“数据当代码”这件事上。
说到底,XSS利用的是应用程序对用户输入缺乏正确的输出编码。它不是某个具体函数写错了,而是一种系统性的疏忽:开发者以为前端会过滤、后端会验证、浏览器会兜底。实际上每个环节都得独立做好自己的事。浏览器不会读心术,它只能按照你给的HTML去解析。你把用户输入原样放进去,浏览器就原样执行。就这么简单,也这么危险。
```友情链接