
每年双 11 大促前夕安全团队与黑产对抗的硝烟味比任何时候都要浓烈。百亿级红包津贴、大额满减券、超低价秒杀库存在灰产集团眼里就是白花花的真金白银。很多业务研发同学有一个误区以为安全防御完全是后端 WAF 和风控网关的事情。然而在高度复杂的现代 Web 应用中前端一旦失守后端的风控规则就会沦为盲人摸象恶意注入的第三方广告脚本可以在客户端静默窃取用户 TokenPuppeteer 自动化无头浏览器可以批量模拟人类点击领券反编译出来的明文接口参数可以被高并发脚本重放无数次。大促前端安全不是单点布防而是一场从页面上下文隔离、脚本反自动化探测到传输层动态签名的全景战役。本文梳理了我们在大促前夕逐项排查落地的前端安全战备核心清单。战备项一严格的 CSP 3.0 策略与 DOM 隔离核验Content Security Policy内容安全策略是抵御跨站脚本攻击XSS与恶意供应链投毒的最坚固防线。落地核验标准彻底铲除unsafe-inline与unsafe-eval生产环境构建时打包工具必须为所有合法的script注入基于 SHA-256 的散列Hash或单次随机数Nonce。严禁在任何第三方 SDK 或业务组件中使用new Function()或eval()。严格收敛connect-src严禁配置通配符*必须精确列出允许通信的业务域名、多云备份域名、CDN 资源域以及指定的上报 APM 域名。强制生效策略指令Content-Security-Policy: default-src self; script-src self nonce-rAnd0m12345 https://trusted-cdn.mall.com; style-src self unsafe-inline https://trusted-cdn.mall.com; connect-src self https://api.mall.com https://api-backup.mall.com https://apm.mall.com; img-src self data: blob: https://img.mallcdn.com; object-src none; base-uri self; frame-ancestors none;通过配置frame-ancestors none彻底封杀任何通过iframe钓鱼嵌套实施的点击劫持Clickjacking攻击。战备项二无头浏览器与反自动化脚本感知Anti-Bot黑产抢购绝大部分依赖于无头浏览器Headless Chrome、Puppeteer、Playwright。这类环境虽然极度逼真但由于其自动控制协议的注入在浏览器底层运行时中不可避免地留下了蛛丝马迹。我们在提单与领券前端组件中内联了一套微秒级、无感知的环境特征探针export interface EnvironmentFingerprint { isAutomated: boolean; tamperedProperties: string[]; webdriverDetected: boolean; } export class ClientIntegrityScanner { public static scan(): EnvironmentFingerprint { const tampered: string[] []; // 1. 标准自动化标记检测 const hasWebdriver navigator.webdriver true; if (hasWebdriver) tampered.push(navigator.webdriver); // 2. 无头环境特有插件缺失检测 // 真实 Chrome 浏览器 navigator.plugins 长度绝不为 0 if (navigator.plugins navigator.plugins.length 0) { tampered.push(empty_plugins); } // 3. 原生方法 toString 被篡改检测黑产常用 Object.defineProperty 伪造属性 try { const proto Object.getPrototypeOf(navigator); const descriptor Object.getOwnPropertyDescriptor(proto, webdriver); if (descriptor descriptor.get) { const fnString descriptor.get.toString(); // 原生 C 绑定的函数其 toString 必然包含 [native code] if (!fnString.includes([native code])) { tampered.push(webdriver_hooked); } } } catch (e) { // 捕获潜在异常 } // 4. 控制台与自动化标志变量探测 const win window as any; if (win._phantom || win.__nightmare || win.callPhantom || win.Buffer) { tampered.push(automation_globals); } return { isAutomated: tampered.length 0, tamperedProperties: tampered, webdriverDetected: hasWebdriver, }; } }在提交请求时若isAutomated为true前端不当场报错阻断防止给黑客当调试反馈而是将异常特征隐式加盐混入签名载荷中由后端风控直接打入“黑产灰度队列”返回虚假的“库存已被抢完”。战备项三基于 Web Crypto API 的请求动态加签与防重放对于领券与秒杀接口绝对禁止明文传输裸请求。一旦请求体被抓包攻击者可以使用脚本以几毫秒的间隔不断重放同一份报文。我们采用时间戳 客户端单次随机串Nonce 请求体哈希的 HMAC-SHA256 签名机制完全基于浏览器原生SubtleCrypto硬件加速零三方库开销export class RequestSecuritySigner { private static cryptoKey: CryptoKey | null null; // 初始化签名密钥在打包时混淆混入或由服务端启动握手动态下发 public static async initKey(secret: string): Promisevoid { const enc new TextEncoder(); const keyData enc.encode(secret); this.cryptoKey await crypto.subtle.importKey( raw, keyData, { name: HMAC, hash: SHA-256 }, false, [sign] ); } // 为请求生成防篡改与防重放签名头 public static async generateSignature( path: string, payloadString: string ): Promise{ timestamp: number; nonce: string; signature: string } { if (!this.cryptoKey) { throw new Error(Signer key not initialized); } const timestamp Date.now(); // 生成密码学安全的 16 字节随机 Nonce const randomBytes new Uint8Array(16); crypto.getRandomValues(randomBytes); const nonce Array.from(randomBytes, (b) b.toString(16).padStart(2, 0)).join(); // 组装待签名串Path Timestamp Nonce Payload const signString ${path}|${timestamp}|${nonce}|${payloadString}; const enc new TextEncoder(); const signatureBuffer await crypto.subtle.sign( HMAC, this.cryptoKey, enc.encode(signString) ); // 转换为十六进制字符串 const signature Array.from(new Uint8Array(signatureBuffer), (b) b.toString(16).padStart(2, 0) ).join(); return { timestamp, nonce, signature }; } }服务端防重放校验规则服务端校验timestamp与服务器当前时间的偏差若超过 30 秒直接判定为过期失效将nonce存入分布式 Redis设置 60 秒 TTL。如果相同的nonce再次出现立刻判定为重放攻击直接拒绝并报警。战备核验与巡检检查表Checklist在大促封版Code Freeze之前前端工程必须严格对照以下矩阵逐项核验并在测试环境进行完整穿透压测CSP 策略线上模式切换确认策略从Content-Security-Policy-Report-Only正式转为强制阻断的Content-Security-Policy。关键凭据无明文暴露代码中绝对禁止存在任何未混淆的静态 Secret统一通过 Diffie-Hellman 动态密钥协商或一次性 Token 换取。敏感 API 挂载防篡改检测提单与领券接口强制挂载ClientIntegrityScanner与 HMAC 动态签名头部。第三方 SDK 权限彻底清查对引入的第三方埋点、客服脚本进行严格审计禁止其监听敏感表单如支付密码、手机号输入框的input事件。生产环境 SourceMap 隔离确认生产打包配置已彻底关闭内联 SourceMap仅允许将独立.map文件上传至内部监控集群CDN 线上严禁暴露源代码映射。防御从来不是一次性的补丁而是一个环环相扣的纵深防御体系。在双 11 狂欢的表象之下用最严密的工程规范构筑起数字长城才是大厂前端安全最坚定的承诺。