JavaScript安全编程关键在于识别执行上下文、控制数据流向、阻断不可信输入自动求值;需避免innerHTML拼接、慎用eval/JSON.parse、正确配置CSP、防范原型污染,并从首行异步请求起贯彻可信数据假设。
JavaScript 安全编程不是靠加一层“防护库”就能解决的,关键在于识别执行上下文、控制数据流向、阻断不可信输入的自动求值路径。不处理好这三点,DOMPurify 或 CSP 都可能被绕过。
这是 XSS 最常见入口。哪怕只插入一个用户昵称,若未转义就写入 innerHTML,攻击者传入 就能触发执行。
实操建议:
textContent 设置纯文本内容;DOMPurify.sanitize() 处理后再赋值,且禁用 ALLOWED_TAGS 中的 script、onerror 等危险项;eval()、Function()、setTimeout(string) 执行动态字符串;`${userInput}`)不等于安全 —— 它只是拼接,不是自动转义。当后端返回的数据结构不可控(如开放 API、第三方 widget 回调),直接 JSON.parse(input) 可能触发原型污染或配合 __proto__ 注入篡改全局行为。
实操建议:
JSON.parse(input, (key, value) => { if (key === '__proto__' || key === 'constructor') return undefined; return value; }) 过滤敏感键;zod 或 yup 做 schema 校验,而非仅靠 typeof 判断;Object.prototype 或任意对象的 __proto__。CSP 是最后一道防线,但只靠 meta 标签声明或漏掉 script-src 的 'unsafe-eval' 限制,等于没设。
实操建议:
meta:设置 Content-Security-Policy: default-src 'self'; script-src 'self' https://cdn.example.com; object-src 'none'; base-uri 'self';;unsafe-inline,内联脚本改用 nonce 或 hash(如 script-src 'self' 'sha256-abc123...');report-uri 或 report-to 收集违规日志,别只写 default-src 'none' 却不监控;eval() 类函数默认被 script-src 拦截,但若你写了 'unsafe-eval',CSP 就形同虚设。像 lodash.merge、Object.assign、JSON.parse(配合恶意 key)都可能污染 Object.prototype,导致后续所有对象意外拥有攻击者注入的方法或属性。
实操建议:
lodash@4.17.21+,并避免对用户输入调用 _.merge({}, userInput);__proto__、constructor、prototype;if (obj?.__proto__ !== undefined || obj?.constructor !== undefined) throw new Error('Prototype pollution detected');Object.freeze(Object.prototype)(注意兼容性,部分老库会报错)。最常被忽略的一点:安全不是「写完功能再加固」,而是从第一个 fetch().then(res => res.json()) 开始,就要问——这个 res 的 shape 是否完全可控?它有没有可能被中间人篡改?有没有可能被前端缓存污染?这些问题的答案,决定了后续所有防御措施是否有效。