# Web 前端安全,如何防止 XSS 攻击

随着互联网的高速发展

信息安全问题已经成为企业最为关注的焦点之一,而前端又是引发企业安全问题的高危据点

  • 在移动互联网时代,前端人员除了传统的 XSS、CSRF 等安全问题之外,又时常遭遇网络劫持、非法调用 Hybrid API 等新型安全问题。
  • 当然,浏览器自身也在不断在进化和发展,不断引入 CSP、Same-Site Cookies 等新技术来增强安全性,但是仍存在很多潜在的威胁,这需要前端技术人员不断进行“查漏补缺”

近几年,随着业务高速发展,前端随之面临很多安全挑战,因此积累了大量的实践经验。
我们梳理了常见的前端安全问题以及对应的解决方案,将会做成一个系列,希望可以帮助前端人员在日常开发中不断预防和修复安全漏洞。

# 1、什么是 XSS ?

XSS 解析


  • Cross-Site Scripting(跨站脚本攻击)简称 XSS,是一种代码注入攻击。
  • 攻击者通过在目标网站上注入恶意脚本,使之在用户的浏览器上运行。
  • 利用这些恶意脚本,攻击者可获取用户的敏感信息如 Cookie、SessionID 等,进而危害数据安全。

为了和 CSS 区分,这里把攻击的第一个字母改成了 X,于是叫做 XSS。

# 2、XSS 的本质

本质

  • 恶意代码未经过滤,与网站正常的代码混在一起;
  • 浏览器无法分辨哪些脚本是可信的,导致恶意脚本被执行。
  • 而由于直接在用户的终端执行,恶意代码能够直接获取用户的信息,或者利用这些信息冒充用户向网站发起攻击者定义的请求。

# 3、用户是通过哪种方法 “注入” 恶意脚本的呢 ?

注入恶意脚本的方式

不仅仅是业务上的“用户的 UGC 内容”可以进行注入,还包括 URL 上的参数等都可以是攻击的来源。在处理输入时,以下内容都不可信:

  • 来自用户的 UGC 信息,UGC(称为 User Generated Content,也就是用户生成内容,即用户原创内容)
  • 来自第三方的链接
  • URL 参数
  • POST 参数
  • Referer (可能来自不可信的来源)
  • Cookie (可能来自其他子域注入)

# 4、据攻击的来源,XSS 攻击可分为存储型、反射型和 DOM 型三种

XSS 攻击的 3 种类型


类型 存储区 插入点
存储型 XSS 后端数据库 HTML
反射型 XSS URL HTML
DOM 型 XSS 后端数据库/前端存储/URL 前端 JavaScript
  • 存储区:恶意代码存放的位置。
  • 插入点:由谁取得恶意代码,并插入到网页上。

# (1)存储型 XSS 的攻击步骤:

  • ① 攻击者将恶意代码提交到目标网站的数据库中。
  • ② 用户打开目标网站时,网站服务端将恶意代码从数据库取出,拼接在 HTML 中返回给浏览器。
  • ③ 用户浏览器接收到响应后解析执行,混在其中的恶意代码也被执行。
  • ④ 恶意代码窃取用户数据并发送到攻击者的网站,或者冒充用户的行为,调用目标网站接口执行攻击者指定的操作。

这种攻击常见于带有用户保存数据的网站功能,如论坛发帖、商品评论、用户私信等。


# (2)反射型 XSS 的攻击步骤:

  • ① 攻击者构造出特殊的 URL,其中包含恶意代码。
  • ② 用户打开带有恶意代码的 URL 时,网站服务端将恶意代码从 URL 中取出,拼接在 HTML 中返回给浏览器。
  • ③ 用户浏览器接收到响应后解析执行,混在其中的恶意代码也被执行。
  • ④ 恶意代码窃取用户数据并发送到攻击者的网站,或者冒充用户的行为,调用目标网站接口执行攻击者指定的操作。

反射型 XSS 与 存储型 XSS 的区别是

  • 存储型 XSS 的恶意代码存在数据库里,反射型 XSS 的恶意代码存在 URL 里。
  • 反射型 XSS 漏洞常见于通过 URL 传递参数的功能,如网站搜索、跳转等。
  • 由于需要用户主动打开恶意的 URL 才能生效,攻击者往往会结合多种手段诱导用户点击。
  • POST 的内容也可以触发反射型 XSS,只不过其触发条件比较苛刻(需要构造表单提交页面,并引导用户点击),所以非常少见。

# (3)DOM 型 XSS 的攻击步骤:

  • ① 攻击者构造出特殊的 URL,其中包含恶意代码。
  • ② 用户打开带有恶意代码的 URL。
  • ③ 用户浏览器接收到响应后解析执行,前端 JavaScript 取出 URL 中的恶意代码并执行。
  • ④ 恶意代码窃取用户数据并发送到攻击者的网站,或者冒充用户的行为,调用目标网站接口执行攻击者指定的操作。

DOM 型 XSS 与 前两种 XSS 的区别:

DOM 型 XSS 攻击中,取出和执行恶意代码由浏览器端完成,属于前端 JavaScript 自身的安全漏洞,而其他两种 XSS 都属于服务端的安全漏洞。

# 5、系统总结 XSS 有哪些注入的方法 ?

总结

  • 在 HTML 中内嵌的文本中,恶意内容以 script 标签形成注入
  • 在内联的 JavaScript 中,拼接的数据突破了原本的限制(字符串,变量,方法名等)
  • 在标签属性中,恶意内容包含引号,从而突破属性值的限制,注入其他属性或者标签
  • 在标签的 href、src 等属性中,包含 javascript: 等可执行代码
  • 在 onload、onerror、onclick 等事件中,注入不受控制代码
  • 在 style 属性和标签中,包含类似 background-image:url("javascript:..."); 的代码(新版本浏览器已经可以防范)
  • 在 style 属性和标签中,包含类似 expression(...) 的 CSS 表达式代码(新版本浏览器已经可以防范)

总之,如果开发者没有将用户输入的文本进行合适的过滤,就贸然插入到 HTML 中,这很容易造成注入漏洞。攻击者可以利用漏洞,构造出恶意的代码指令,进而利用恶意代码危害数据安全。

# 6、系统总结:XSS 攻击防范措施

总结

整体的 XSS 防范是非常复杂和繁琐的,我们不仅需要在全部需要转义的位置,对数据进行对应的转义。而且要防止多余和错误的转义,避免正常的用户输入出现乱码。

虽然很难通过技术手段完全避免 XSS,但我们可以总结以下原则减少漏洞的产生:

  • 利用模板引擎 开启模板引擎自带的 HTML 转义功能。例如:

    • 在 ejs 中,尽量使用 <%= data %> 而不是 <%- data %>
    • 在 doT.js 中,尽量使用 {{! data } 而不是 {{= data }
    • 在 FreeMarker 中,确保引擎版本高于 2.3.24,并且选择正确的 freemarker.core.OutputFormat
  • 避免内联事件 尽量不要使用 onLoad="onload('')"onClick="go('')" 这种拼接内联事件的写法。在 JavaScript 中通过 .addEventlistener() 事件绑定会更安全。

  • 避免拼接 HTML 前端采用拼接 HTML 的方法比较危险,如果框架允许,使用 createElementsetAttribute 之类的方法实现。

  • 或者采用比较成熟的渲染框架,如 Vue/React 等。

  • 时刻保持警惕 在插入位置为 DOM 属性、链接等位置时,要打起精神,严加防范。

  • 增加攻击难度,降低攻击后果 通过 CSP、输入长度配置、接口安全措施等方法,增加攻击的难度,降低攻击的后果。

  • 主动检测和发现 可使用 XSS 攻击字符串和自动扫描工具寻找潜在的 XSS 漏洞。

基础防范措施:

  • ①、对富文本编辑器,过滤 script 等不安全标签
  • ②、对用户输入进行转义,比如把<script></script> 转义为 &lt;script&gt; &lt;/script&gt;
  • ③、代码需要动态展示内容时用 innerText 取代 innerHTML ,使用 v-text 取代 v-html,尽量少做 HTML 字符串拼接,禁止使用 eval 执行 JS。
  • ④、服务端 Set Cookie 时 带上 HttpOnly 字段,阻止 JavaScript 获取 Cookie
  • ⑤、对于上传图片的场景,禁止使用用户填写的图片地址。特别是 Markdown 编辑器。

# (1)预防 DOM 型 XSS 攻击

DOM 型 XSS 攻击

实际上就是网站前端 JavaScript 代码本身不够严谨,把不可信的数据当作代码执行了。

  • 在使用 .innerHTML.outerHTMLdocument.write() 时要特别小心

    • 不要把不可信的数据作为 HTML 插到页面上
    • 而应尽量使用 .textContent.setAttribute() 等。
  • 如果用 Vue/React 技术栈

    • 不使用 v-html/dangerouslySetInnerHTML 功能
    • 就在前端 render 阶段避免 innerHTMLouterHTML 的 XSS 隐患。
  • DOM 中的内联事件监听器,如 locationonclickonerroronloadonmouseover

    • <a> 标签的 href 属性
    • JavaScript 的 eval()setTimeout()setInterval() 等,都能把字符串作为代码运行。
    • 如果不可信的数据拼接到字符串中传递给这些 API,很容易产生安全隐患,请务必避免。

# (2)Content Security Policy (内容安全策略)

严格的 CSP 在 XSS 的防范中可以起到以下的作用:

  • 禁止加载外域代码,防止复杂的攻击逻辑。
  • 禁止外域提交,网站被攻击后,用户的数据不会泄露到外域。
  • 禁止内联脚本执行(规则较严格,目前发现 GitHub 使用)。
  • 禁止未授权的脚本执行(新特性,Google Map 移动版在使用)。
  • 合理使用上报可以及时发现 XSS,利于尽快修复问题。

# (3)输入内容长度控制

TIP

  • 对于不受信任的输入,都应该限定一个合理的长度。
  • 虽然无法完全防止 XSS 发生,但可以增加 XSS 攻击的难度。

# (4)其他安全措施

TIP

  • HTTP-only Cookie: 禁止 JavaScript 读取某些敏感 Cookie,攻击者完成 XSS 注入后也无法窃取此 Cookie。
  • 验证码:防止脚本冒充用户提交危险操作。
上次更新时间: 6/8/2023, 9:23:17 PM

大厂最新技术学习分享群

大厂最新技术学习分享群

微信扫一扫进群,获取资料

X