一个晴朗的下午,我盯着Burp Suite里那个被标红的请求包,嘴角忍不住上扬。参数?search=后面塞进去的<script>alert(1)</script>,居然原封不动地弹了回来。那一刻我突然意识到,这个看似人畜无害的搜索框,就是整站最脆弱的后门。
XSS攻击的本质很简单——你把用户输入当成了代码来执行。但真正让我脊背发凉的,是它的传播方式。存储型XSS就像一颗定时炸弹,你把它埋进评论区、个人资料、甚至URL里,等管理员一登录,Cookie就到手了。我见过最离谱的一次,攻击者只是在一个论坛的签名档里藏了段JS,结果三天后,整个版主的账号全被洗了一遍。
反射型XSS倒是直来直去,你点我构造的链接,我就拿到你的会话。但别小看它,配合短链接和钓鱼页面,照样能骗过大部分小白。DOM型XSS更阴险,它根本不经过服务器,直接在浏览器里改DOM结构。我曾经在某个单页应用里,只靠修改location.hash就绕过了所有过滤规则——因为前端框架压根没把hash当输入处理。
防御手段说起来头头是道:转义输出、CSP头、HttpOnly标记……可现实总是打脸。上周我帮朋友审计一个政府网站,开发人员确实加了htmlspecialchars(),但没注意编码问题,<svg/onload=alert(1)>照样能穿透。更讽刺的是,他们用了最新的框架,却在某个遗留接口里手动拼接了HTML。
别以为XSS只是弹个窗那么简单。真正的杀手锏是结合CSRF——你登录着银行页面,我通过XSS注入一段表单自动提交的脚本,转账操作根本不需要你点击。还有个更野的路子,用XSS挖矿。去年有个案例,黑客在视频网站评论区植入挖矿脚本,看视频的人CPU飙到90%还浑然不觉,电费全算在受害者头上。
说句得罪人的话,很多程序员对XSS的认知还停留在“过滤尖括号”的阶段。但现代XSS早就进化了——利用javascript:协议、SVG事件、CSS表达式,甚至<iframe>的srcdoc属性都能绕过。最典型的是绕过onerror过滤,改用<img src=x onerror=eval(atob('...'))>,Base64编码一糊,正则表达式直接歇菜。
写到这里,我想起那个下午的后续。我并没有提交漏洞报告,而是默默关掉了Burp Suite。因为那个搜索框属于一个公益募捐平台,后台连着无数志愿者的个人信息。在漏洞修复之前,我不确定自己是在做安全测试,还是在给黑暗递刀子。XSS的可怕之处从来不在于技术本身,而在于你永远不知道屏幕对面坐着的是白帽还是黑产——就像你永远不知道,下一个被弹窗的页面,会把你带到哪里去。