浏览器运行的代码和构建产物可以被用户检查。隐藏按钮、混淆 JavaScript、把密钥放在前端环境变量中,都不能建立服务端权限。访问某个资源是否被允许,必须由服务端根据可信身份和规则判断。
数据进入页面的方式
把输入作为文本显示,与把它解释为 HTML,是不同能力。默认使用 textContent 或框架的正常文本插值。需要渲染用户 HTML 时,应先明确允许哪些内容,再使用经过维护的消毒方案;一串正则替换不足以覆盖浏览器解析规则。
const output = document.createElement("p");
const input = "<b>这是一段输入</b>";
output.textContent = input;
document.body.append(output);
// 页面显示尖括号和标签文字,不生成加粗节点。
这个安全片段可在空白实验页运行。React 的 dangerouslySetInnerHTML、Vue 的 v-html 等显式 HTML 注入入口需要额外审查。富文本中的链接协议、图片、样式和嵌入内容也有各自风险,不能只处理 script 标签。
XSS 可以发生在服务端输出或客户端 DOM 操作中。Content Security Policy 可作为额外防护,通常先通过报告模式观察,再逐步收紧脚本来源和执行方式;它不能代替正确的输出处理。具体部署要核对现有脚本、nonce/hash 与缓存策略。
CSRF 与登录态
当浏览器自动附带 Cookie 时,恶意页面可能诱导发送带身份的请求。状态修改不能只因为“带着 Cookie”就接受。根据应用设计使用 SameSite、CSRF token、Origin 检查等措施,并让 GET 保持安全语义。CORS 主要限制脚本读取跨源响应,并不能阻止所有请求被发送。
HttpOnly 可以限制脚本直接读取 Cookie,但发生 XSS 后,攻击代码仍可能以用户身份操作页面。Secure 约束 HTTPS 传输,SameSite 约束部分跨站发送场景;每个属性解决的问题不同。令牌存储方式应结合威胁模型决定,不能把 localStorage 当成默认保险箱。
依赖、链接和日志
第三方脚本拥有很强的页面能力,加入分析或组件前要评估必要性、来源和更新渠道。固定依赖、检查锁文件变化与及时修补已知漏洞是持续维护,不是安装时做一次扫描就结束。
错误日志应避免记录密码、令牌和完整私人内容。外链只接受预期协议;上传接口还需由服务端校验文件内容、大小、权限及保存方式。前端的 accept 和扩展名检查只帮助选择文件。
练习:审阅一个新增记录表单,标出文本、HTML、URL、请求体和日志五个数据边界。给每个边界写出处理方式,再用普通带尖括号文本验证展示不会变成 DOM。
面试自查:XSS 和 CSRF 的前提有什么区别?HttpOnly 为什么不能彻底阻止 XSS 后的操作?为什么 CORS 放开与服务端授权是两件事?