|
跨站脚本攻击(XSS)的跨站本质是:用户输入被当成代码执行了。听起来简单,脚本解决但每年仍有大量网站栽在这上面。攻击我见过一个电商站,跨站搜索框里输入 <script>alert(1)</script>,脚本解决页面直接弹窗。攻击更糟的跨站是,攻击者能通过这个漏洞偷走用户的脚本解决 Cookie,冒充登录。攻击这不是跨站理论,是脚本解决真实发生过的案例。 要解决 XSS,攻击得先分清它的跨站三种类型。反射型最直接:恶意链接诱导用户点击,脚本解决脚本随请求打到服务器,攻击再反射回浏览器执行。存储型更危险:攻击者把脚本存进数据库,比如评论区,所有访问该页面的用户都会中招。DOM 型则完全在浏览器端发生,服务器甚至不知道脚本被注入了。我判断一个团队是否重视安全,就看他们有没有针对这三种类型分别做测试。 输出编码是最后一道防线,也是最重要的一道。原则很简单:根据上下文决定编码方式。HTML 正文里,把 < 转成 <,> 转成 >;属性值里,还要处理引号;JavaScript 代码块里,得用 Unicode 转义。很多开发者偷懒,统一用 HTML 实体编码,结果在 onclick 事件里照样被绕过。我见过有人把用户输入直接塞进 href,以为编码了就安全,结果 javascript:alert(1) 照样执行。上下文不同,规则就不同。 输入验证有用,但别指望它。白名单过滤(比如只允许字母数字)能挡住大部分低级攻击,可一旦业务需要富文本,比如允许用户加粗、插入链接,白名单就失效了。这时候得靠 HTML 净化库,比如 DOMPurify。我试过自己写正则过滤 <script>,结果被 <img src=x onerror=alert(1)> 轻松绕过。专业库经过大量测试,别自己造轮子。 Content Security Policy(CSP)是第二道防线。设置 Content-Security-Policy: default-src 'self',浏览器就只执行同源脚本,内联脚本和 eval 默认被禁。但 CSP 配置很麻烦,很多站点为了兼容旧代码,不得不加 'unsafe-inline',等于白设。我的建议是:新项目从一开始就上严格 CSP,老项目逐步迁移。别等到被攻击了才想起来。 HttpOnly 标志能保护 Cookie 不被 JavaScript 读取。设置 Set-Cookie: sessionid=xxx; HttpOnly,即使 XSS 存在,攻击者也偷不走会话。但这不是万能药——攻击者仍能发起请求,冒充用户操作。所以 HttpOnly 是减伤,不是免疫。 框架层面,React、Vue 默认对插值做转义,但 dangerouslySetInnerHTML 和 v-html 是逃生舱。我审查过不少项目,开发者为了渲染富文本,直接开这个口子,然后忘了净化。框架帮你挡了 90% 的坑,剩下 10% 得自己填。 最后说个真实观察:很多团队修 XSS 只修报告里那一个点,不排查同类接口。结果同一个参数,换个路径又中招。正确做法是全局搜索所有输出点,统一加编码。安全不是打补丁,是改代码习惯。 |