FORMA

安全

前端安全侧重在浏览器侧降低 XSS、CSRF、点击劫持等风险;最终防护须服务端配合(校验、鉴权、安全响应头)。

一、XSS(跨站脚本攻击)

XSS 攻击指攻击者将恶意脚本注入网页,当其他用户浏览时执行,从而窃取数据、劫持会话或篡改页面。

1. 三种类型

类型触发方式特点
反射型恶意脚本作为 URL 参数或表单数据,服务器直接返回该脚本并在页面中执行。非持久,需诱骗用户点击恶意链接。
存储型恶意脚本被存储在后端数据库或文件系统中,当其他用户访问受影响页面时执行。持久性,影响范围广(如评论区、留言板)。
DOM 型完全在前端发生,恶意脚本来自 document.locationdocument.referrer 等,通过 innerHTMLeval 等动态执行。不经过服务器,纯前端注入。

2. 防御措施

  • 输出转义(编码):根据上下文对用户输入进行转义。
    • HTML 上下文:转义 <, >, &, ", ' 等为实体。
    • HTML 属性:转义引号。
    • JavaScript 上下文:使用 JSON.stringify 或转义换行符等。
    • CSS 上下文:限制输入或转义特殊字符。
    • URL 上下文:使用 encodeURIComponent
  • 使用安全 API
    • textContentinnerText 替代 innerHTMLouterHTML
    • 设置 element.setAttribute 时避免使用 hrefonclick 等可执行属性。
  • 内容安全策略(CSP):通过 HTTP 头声明允许的资源来源。
    http
    Content-Security-Policy: default-src 'self'; script-src 'self' https://trusted.cdn.com
    
    关键指令:script-src 'nonce-...''strict-dynamic',可有效阻止内联脚本执行。
  • HTTP-only Cookie:将敏感 Cookie 标记为 HttpOnly,使 JavaScript 无法读取,即使 XSS 也无法窃取 Session ID。
  • 输入验证:对特定类型输入(如 email、数字)进行格式校验,拒绝或净化危险字符(但黑名单易绕过,推荐白名单)。

二、CSRF(跨站请求伪造)

CSRF 攻击诱导用户当前已认证的浏览器向目标网站发送非本意的请求(如转账、修改密码),利用用户身份执行操作。

防御措施

  1. CSRF Token(同步令牌)
    • 服务器生成随机 token,嵌入表单或请求头中。
    • 后端验证请求中的 token 是否与会话中的匹配。
    • 攻击者无法读取页面中的 token(受同源策略保护)。
  2. SameSite Cookie 属性
    • SameSite=Lax:跨站 GET 请求(如点击链接)可携带 Cookie,但 POST 等不安全方法不携带。
    • SameSite=Strict:任何跨站请求均不携带 Cookie。
    • SameSite=None; Secure:允许跨站携带,但必须 HTTPS 且显式设置,一般不推荐用于防 CSRF。
  3. 验证 Referer / Origin 头
    • 在服务端检查请求头的 OriginReferer 是否来自可信源。
    • 注意:某些场景可能被省略或篡改,作为辅助手段。
  4. 双重 Cookie 验证(适用于某些 SPA)
    • 在 Cookie 中设置一个随机值,同时在请求头或参数中发送相同值,后端比对。
  5. 用户交互验证:对关键操作加入图形验证码、重新输入密码等。

三、点击劫持(Clickjacking)

攻击者通过透明 iframe 覆盖合法页面,诱使用户在不知情的情况下点击隐藏按钮或链接,执行恶意操作(如添加权限、转发消息)。

防御措施

  1. X-Frame-Options 响应头
    • DENY:禁止任何页面嵌入 iframe。
    • SAMEORIGIN:只允许同源页面嵌入。
    • ALLOW-FROM uri(已废弃,不推荐)。
  2. Content-Security-Policy 的 frame-ancestors
    http
    Content-Security-Policy: frame-ancestors 'none'
    Content-Security-Policy: frame-ancestors 'self' https://trusted.com
    

    现代浏览器优先支持 frame-ancestors,可替代 X-Frame-Options
  3. 窗口逃逸防御(前端辅助):在页面中通过 JavaScript 判断自身是否在顶层,若不是则强制跳出。
    js
    if (top !== self) top.location = self.location;
    

    注意可能被攻击者规避(如 sandbox 属性),只能作为补充。

四、不安全第三方依赖

使用第三方库可能引入已知漏洞(如原型污染、XSS)或导致正则表达式拒绝服务(ReDoS)。

1. ReDoS(正则表达式拒绝服务)

恶意构造的字符串可使某些正则表达式引擎进入灾难性回溯,消耗大量 CPU,导致服务不可用。

典型危险模式

  • 嵌套量词:(a+)+(a|a)+(a*)*
  • 重叠的分组与选择:a*ba*ab

防御

  • 使用原子分组(如 (?>a+))或占有量词(如 ++),但 JS 标准正则不支持;可借助 RegExp.prototype.exec 手动控制。
  • 使用 new RegExp 时对用户输入进行转义(escapeRegex 函数)。
  • 限制输入长度,超时机制(使用 Promise.raceWorker 强制中断)。
  • 使用简单正则或改用非回溯算法库(如 RE2 通过 WebAssembly 集成)。
  • 定期运行 npm audit,使用 SnykDependabot 检测脆弱正则。

2. 供应链攻击

  • 锁定依赖版本,使用 package-lock.json / yarn.lock
  • 审查第三方包来源,避免使用未维护或低信誉包。
  • 实施软件材料清单(SBOM)并监控 CVE 数据库。

五、evalnew Function 的风险

两者都允许动态执行 JavaScript 字符串,带来严重安全隐患:

  • XSS 放大:攻击者若控制字符串内容,可直接执行任意代码,绕过 CSP 等防御。
  • 作用域污染与变量泄露eval 可访问本地作用域,new Function 仅访问全局作用域,但依然危险。
  • 性能下降:现代引擎无法对动态代码进行有效优化,且阻止某些静态分析。
  • 难以审计:动态代码使安全审查变得几乎不可能。

安全使用原则

  • 绝对避免:永远不要使用 evalnew Function 处理用户输入。
  • 极少数合法场景
    • 框架模板编译(在安全沙箱中,如 Vue/React 的底层渲染函数,通常使用 new Function,但仅作用于开发者信任的模板)。
    • 在线代码演练(如 CodePen)需在严格隔离的 iframe + sandbox 中执行。
  • 替代方案
    • 使用 JSON.parse 代替 eval 解析数据。
    • 动态属性访问:使用 obj[prop] 代替字符串构建代码。
    • 若需动态函数,使用预定义映射表。
  • CSP 加固:设置 script-src 'unsafe-eval' 不包含(即禁止 eval 及类似方法),现代项目应默认禁止。

总结

威胁核心防御
XSS输出转义 + CSP + HttpOnly Cookie + 安全 API (innerText)
CSRFCSRF 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 ForgeryCSRF 概念
OWASP:XSS PreventionXSS 防护(英文)
OWASP:CSRF PreventionCSRF 防护(英文)