安全
前端安全侧重在浏览器侧降低 XSS、CSRF、点击劫持等风险;最终防护须服务端配合(校验、鉴权、安全响应头)。
一、XSS(跨站脚本攻击)
XSS 攻击指攻击者将恶意脚本注入网页,当其他用户浏览时执行,从而窃取数据、劫持会话或篡改页面。
1. 三种类型
| 类型 | 触发方式 | 特点 |
|---|---|---|
| 反射型 | 恶意脚本作为 URL 参数或表单数据,服务器直接返回该脚本并在页面中执行。 | 非持久,需诱骗用户点击恶意链接。 |
| 存储型 | 恶意脚本被存储在后端数据库或文件系统中,当其他用户访问受影响页面时执行。 | 持久性,影响范围广(如评论区、留言板)。 |
| DOM 型 | 完全在前端发生,恶意脚本来自 document.location、document.referrer 等,通过 innerHTML、eval 等动态执行。 | 不经过服务器,纯前端注入。 |
2. 防御措施
- 输出转义(编码):根据上下文对用户输入进行转义。
- HTML 上下文:转义
<,>,&,",'等为实体。 - HTML 属性:转义引号。
- JavaScript 上下文:使用
JSON.stringify或转义换行符等。 - CSS 上下文:限制输入或转义特殊字符。
- URL 上下文:使用
encodeURIComponent。
- HTML 上下文:转义
- 使用安全 API:
textContent或innerText替代innerHTML、outerHTML。- 设置
element.setAttribute时避免使用href或onclick等可执行属性。
- 内容安全策略(CSP):通过 HTTP 头声明允许的资源来源。
关键指令:http
Content-Security-Policy: default-src 'self'; script-src 'self' https://trusted.cdn.comscript-src 'nonce-...'或'strict-dynamic',可有效阻止内联脚本执行。 - HTTP-only Cookie:将敏感 Cookie 标记为
HttpOnly,使 JavaScript 无法读取,即使 XSS 也无法窃取 Session ID。 - 输入验证:对特定类型输入(如 email、数字)进行格式校验,拒绝或净化危险字符(但黑名单易绕过,推荐白名单)。
二、CSRF(跨站请求伪造)
CSRF 攻击诱导用户当前已认证的浏览器向目标网站发送非本意的请求(如转账、修改密码),利用用户身份执行操作。
防御措施
- CSRF Token(同步令牌)
- 服务器生成随机 token,嵌入表单或请求头中。
- 后端验证请求中的 token 是否与会话中的匹配。
- 攻击者无法读取页面中的 token(受同源策略保护)。
- SameSite Cookie 属性
SameSite=Lax:跨站 GET 请求(如点击链接)可携带 Cookie,但 POST 等不安全方法不携带。SameSite=Strict:任何跨站请求均不携带 Cookie。SameSite=None; Secure:允许跨站携带,但必须 HTTPS 且显式设置,一般不推荐用于防 CSRF。
- 验证 Referer / Origin 头
- 在服务端检查请求头的
Origin或Referer是否来自可信源。 - 注意:某些场景可能被省略或篡改,作为辅助手段。
- 在服务端检查请求头的
- 双重 Cookie 验证(适用于某些 SPA)
- 在 Cookie 中设置一个随机值,同时在请求头或参数中发送相同值,后端比对。
- 用户交互验证:对关键操作加入图形验证码、重新输入密码等。
三、点击劫持(Clickjacking)
攻击者通过透明 iframe 覆盖合法页面,诱使用户在不知情的情况下点击隐藏按钮或链接,执行恶意操作(如添加权限、转发消息)。
防御措施
- X-Frame-Options 响应头
DENY:禁止任何页面嵌入 iframe。SAMEORIGIN:只允许同源页面嵌入。ALLOW-FROM uri(已废弃,不推荐)。
- Content-Security-Policy 的
frame-ancestorshttpContent-Security-Policy: frame-ancestors 'none' Content-Security-Policy: frame-ancestors 'self' https://trusted.com
现代浏览器优先支持frame-ancestors,可替代X-Frame-Options。 - 窗口逃逸防御(前端辅助):在页面中通过 JavaScript 判断自身是否在顶层,若不是则强制跳出。js
if (top !== self) top.location = self.location;
注意可能被攻击者规避(如sandbox属性),只能作为补充。
四、不安全第三方依赖
使用第三方库可能引入已知漏洞(如原型污染、XSS)或导致正则表达式拒绝服务(ReDoS)。
1. ReDoS(正则表达式拒绝服务)
恶意构造的字符串可使某些正则表达式引擎进入灾难性回溯,消耗大量 CPU,导致服务不可用。
典型危险模式:
- 嵌套量词:
(a+)+、(a|a)+、(a*)* - 重叠的分组与选择:
a*b与a*ab等
防御:
- 使用原子分组(如
(?>a+))或占有量词(如++),但 JS 标准正则不支持;可借助RegExp.prototype.exec手动控制。 - 使用
new RegExp时对用户输入进行转义(escapeRegex函数)。 - 限制输入长度,超时机制(使用
Promise.race或Worker强制中断)。 - 使用简单正则或改用非回溯算法库(如 RE2 通过 WebAssembly 集成)。
- 定期运行
npm audit,使用Snyk或Dependabot检测脆弱正则。
2. 供应链攻击
- 锁定依赖版本,使用
package-lock.json/yarn.lock。 - 审查第三方包来源,避免使用未维护或低信誉包。
- 实施软件材料清单(SBOM)并监控 CVE 数据库。
五、eval 与 new Function 的风险
两者都允许动态执行 JavaScript 字符串,带来严重安全隐患:
- XSS 放大:攻击者若控制字符串内容,可直接执行任意代码,绕过 CSP 等防御。
- 作用域污染与变量泄露:
eval可访问本地作用域,new Function仅访问全局作用域,但依然危险。 - 性能下降:现代引擎无法对动态代码进行有效优化,且阻止某些静态分析。
- 难以审计:动态代码使安全审查变得几乎不可能。
安全使用原则
- 绝对避免:永远不要使用
eval和new Function处理用户输入。 - 极少数合法场景:
- 框架模板编译(在安全沙箱中,如 Vue/React 的底层渲染函数,通常使用
new Function,但仅作用于开发者信任的模板)。 - 在线代码演练(如 CodePen)需在严格隔离的 iframe +
sandbox中执行。
- 框架模板编译(在安全沙箱中,如 Vue/React 的底层渲染函数,通常使用
- 替代方案:
- 使用
JSON.parse代替eval解析数据。 - 动态属性访问:使用
obj[prop]代替字符串构建代码。 - 若需动态函数,使用预定义映射表。
- 使用
- CSP 加固:设置
script-src 'unsafe-eval'不包含(即禁止eval及类似方法),现代项目应默认禁止。
总结
| 威胁 | 核心防御 |
|---|---|
| XSS | 输出转义 + CSP + HttpOnly Cookie + 安全 API (innerText) |
| CSRF | CSRF Token + SameSite Cookie(Lax/Strict) + Referer/Origin 校验 |
| 点击劫持 | X-Frame-Options / CSP frame-ancestors + 可选的 JS 逃逸 |
| 第三方依赖 | ReDoS:限制输入长度、超时、审计正则;依赖扫描 + 版本锁定 |
| eval / Function | 完全避免,必要情况使用沙箱 + CSP 禁止 'unsafe-eval' |
安全是纵深防御:组合输出编码、CSP、Cookie 属性与服务端校验,并保持依赖更新。
参考文献
以下链接在编写时均可正常访问:
| 资料 | 说明 |
|---|---|
| MDN:内容安全策略 | CSP |
| MDN:Cross-Site Request Forgery | CSRF 概念 |
| OWASP:XSS Prevention | XSS 防护(英文) |
| OWASP:CSRF Prevention | CSRF 防护(英文) |
相关文章
错误处理与调试
结构化错误类型、try/catch 与全局未捕获处理是健壮应用的基础。
浏览器相关 API
DOM 事件、存储、fetch、Worker、Observer 等由浏览器提供的 Web API(非 ECMAScript 核心)。HTML 结构见 标签。
性能优化
防抖/节流、渲染与内存、资源预加载及引擎行为是前端性能的主要抓手。相关 CSS 见 视觉效果、Head 资源提示。
模块化与工程化
ESM、CommonJS 与打包工具(Tree Shaking、代码分割)是前端工程化的基础。入门见 JavaScript 基础 · 模块。
执行模型与作用域
执行上下文与词法作用域决定变量在何处可访问、闭包如何形成,以及 var / let / const 的差异。语言概览见 JavaScript 基础。
数据结构与集合增强
Map / Set、WeakMap / WeakSet、数组高阶方法、TypedArray 与 Symbol 等扩展了内置数据结构能力。见 语言基础。