安全监控
1 XSS 攻击与防御
XSS 三种类型:存储型、反射型、DOM 型
反射型 XSS:攻击代码放到 search 参数里,且网站显示用户内容。用户点击恶意链接,恶意脚本作为请求的一部分发送到服务器,服务器将脚本作为响应返回,脚本在用户浏览器执行。常用于钓鱼邮件。
http://example.com/search?q=<script>alert('XSS');</script>
存储型 XSS:恶意脚本永久存储在目标服务器(数据库、论坛、留言等)。用户浏览含恶意脚本的网页时脚本执行。比反射型更危险,无需诱导点击。
<script>alert('XSS');</script>
DOM 型 XSS:通过修改页面 DOM 实施,完全发生在客户端,不涉及服务器。例如根据 URL 的 # 后内容动态修改页面标题:
document.title = document.location.hash.substring(1);
// 攻击链接:http://example.com/#<script>alert('XSS');</script>
防御 XSS:转义、CSP、HttpOnly、React 自动转义
1. 转义:永远不要相信用户输入,服务端做转义。将 < 转为 <,> 转为 >,浏览器解析时当作普通文本。输入时验证与净化,输出时根据上下文转义。
2. HttpOnly:将重要 cookie 标记为 HttpOnly,JavaScript 无法读取,即使 XSS 成功也无法窃取 cookie。不能阻止 XSS 本身,但可减少损害。
3. CSP(内容安全策略):建立白名单,限制脚本来源、禁止内联脚本、限制其他资源来源。通过 HTTP 头 Content-Security-Policy 或 meta 标签开启。
React 自动转义:React、Vue 等框架默认对插入 DOM 的内容进行转义,避免直接使用 dangerouslySetInnerHTML 或 v-html 插入未验证内容。
CSP 示例与最佳实践
Content-Security-Policy:
default-src 'self';
script-src 'self' https://trustedscripts.example.com;
object-src 'none';
style-src 'self' https://trustedstyles.example.com;
img-src 'self' data:;
report-uri /csp-violation-report-endpoint/;
实践建议:先使用 report-only 模式监控;结合输入验证、输出编码;避免 unsafe-inline 和 unsafe-eval。
2 CSRF 攻击与防御
CSRF 原理与特点
特点:用户已登录;跨站请求;用户不知情。典型场景:Bob 登录银行,Mallory 在自己网站放 <img src="http://bank.example/withdraw?account=10000&amount=2000&for=Mallory">,Bob 访问时若 session 未过期,请求会生效。
防御 CSRF:SameSite、CSRF Token、Referer 检查
1. SameSite Cookie:Strict 完全阻止跨站携带;Lax 允许 GET 且页面跳转的请求携带;None 需配合 Secure。现代浏览器默认 Lax。
Set-Cookie: sessionId=abc123; SameSite=Lax; Secure; HttpOnly
2. CSRF Token:服务器返回随机 token,请求时在表单隐藏字段或请求头中携带,服务器验证。攻击者无法获取 token,无法构造合法请求。
<input type="hidden" name="csrf_token" value="随机生成的Token">
3. Referer/Origin 检查:根据 HTTP 头判断请求来源,非允许站点直接拒绝。缺点:Referer 可被伪造。
SameSite=None 必须配合 Secure
SameSite=None 必须与 Secure 配合使用。浏览器要求如此,否则会拒绝该 Cookie。跨域携带 cookie 需:SameSite=None; Secure + 客户端 credentials: 'include'。3 监控与告警
Sentry 接入与错误捕获
错误捕获方式:window.onerror、window.addEventListener('error') 捕获未捕获错误;window.addEventListener('unhandledrejection') 捕获未处理的 Promise 拒绝;try-catch 捕获特定代码块。
window.onerror = function(message, source, lineno, colno, error) {
Sentry.captureException(error || new Error(message));
};
window.addEventListener('unhandledrejection', function(event) {
Sentry.captureException(event.reason);
});
Source Map 上传与告警策略
生产环境可将产物和 Source Map 分别输出到不同路径,Source Map 上传到 Sentry 等平台用于还原堆栈。Webpack 配置:sourceMapFilename: '../dist_maps/[file].map'。
告警策略:邮件、Slack、微信等渠道;可配置错误级别、频率限制、聚合规则;结合埋点数据做根因分析。
4 埋点方案
埋点与业务解耦 4 层方案
第 1 层:统一埋点适配器——封一层 track(),屏蔽神策/GA/自研平台差异。
第 2 层:事件协议层——集中定义事件名、字段,用 analytics.buyButtonClick({ skuId, price }) 替代散落字符串。
第 3 层:声明式采集——TrackClick 组件、data-track-event 属性、useExposureTrack,全局事件代理统一监听。
document.addEventListener('click', (e) => {
const el = (e.target).closest('[data-track-event]');
if (el) track(el.dataset.trackEvent, { skuId: el.dataset.trackSkuId });
});
第 4 层:业务事件层——复杂流程用 eventBus.emit('order:submit', payload),埋点层订阅映射。
判断标准:去掉埋点实现,业务应能正常运行。
性能埋点与 web-vitals、sendBeacon
性能埋点:使用 web-vitals 等库采集 LCP、FID、CLS 等核心指标。
上报方式:navigator.sendBeacon(url, data) 在页面卸载时可靠发送,不阻塞页面关闭。
5 同源策略与 Cookie
sessionStorage 通信与跨域 cookie
// BroadcastChannel 示例
const channel = new BroadcastChannel('sessionChannel');
channel.postMessage({ type: 'sessionData', data: message });
channel.onmessage = (e) => { /* 接收并存入 sessionStorage */ };
跨域 cookie:需 SameSite=None; Secure,且服务端 CORS 设置 Access-Control-Allow-Credentials: true,客户端 credentials: 'include'。
localStorage 与 sessionStorage 共享限制
同源策略:协议、域名、端口必须一致才能共享。
localStorage:同源所有标签页共享;不同浏览器、隐身模式、设备不共享。
sessionStorage:同一窗口/标签页内唯一;不同窗口不共享;关闭后清除。
6 代码混淆
JavaScript Obfuscator 原理
变量混淆:将变量名、函数名替换为无意义名称,如 _0x123456。
字符串加密:字符串加密或编码,运行时动态解密,防止直接搜索。
死代码注入:插入大量不执行的代码,增加复杂度和干扰逆向。
控制流平坦化:将 if-else、switch、循环改为非线性结构,增加跳转,使执行路径难以预测。
其他:代码压缩、动态代码生成(eval/Function)、常量替换、对象属性混淆、防调试技术。AST 是代码混淆和压缩的基础。