Skip to main content

XSS 跨站脚本攻击

常见的浏览器攻击分为两种,一种为 XSS(跨站脚本攻击),另一种则为 CSRF(跨站请求伪造)

一、XSS 的定义​

XSS(Cross Site Scripting)即跨站脚本攻击,为了与“CSS”区分开来,所以简称 XSS。XSS 攻击是指通过向 HTML 文件或 DOM 中注入恶意脚本,在用户浏览页面时对用户实施攻击的一种手段。

二、XSS 存在原因​

浏览器支持页面引用第三方资源和跨域资源共享(CORS),这带来了很多安全问题,其中最典型的就是 XSS 攻击。

三、XSS 攻击方式​

1、存储型(持久型)XSS 攻击​

存储型(持久型)XSS(Stored XSS)漏洞一般存在于 Form 表单提交等交互功能,如文章留言,提交文本信息等,黑客利用的 XSS 漏洞,将内容经正常功能提交进入数据库持久保存,当前端页面获得后端从数据库中读出的注入代码时,恰好将其渲染执行。

存储型 XSS 的攻击步骤:

  1. 黑客利用站点漏洞将一段恶意 JS 代码提交到网站的数据库中;
  2. 然后用户向网站请求包含了恶意 JS 脚本的页面;
  3. 当用户浏览该页面时,恶意脚本就会将用户的 Cookie 信息等数据上传到服务器。

存储型 XSS 的特点:

  • 持久性,植入在数据库中;
  • 盗取用户敏感私密信息;
  • 危害面广。

2、反射型(非持久型)XSS 攻击​

反射型(非持久型)XSS 漏洞(Reflected XSS),一般是通过给别人发送带有恶意脚本代码参数的 URL,当 URL 地址被打开时,特有的恶意代码参数被 HTML 解析执行。

反射型 XSS 的攻击步骤:

  1. 恶意 JS 脚本属于用户发送给网站请求中的一部分;
  2. 随后网站又把恶意 JS 脚本返回给用户;
  3. 恶意 JS 脚本就可以在用户页面中被执行。

攻击者可以直接通过 URL (类似:https://xxx.com/xxx?default=<script>alert(document.cookie)</script>) 注入可执行的脚本代码。不过一些浏览器如 Chrome 其内置了一些 XSS 过滤器,可以防止大部分反射型 XSS 攻击。

与存储型 XSS 的区别:

存储型 XSS 的恶意代码存在数据库中,而反射型 XSS 的恶意代码存在 URL 中。

3、基于 DOM 的 XSS 攻击​

基于 DOM 的 XSS 攻击(DOM-based or local XSS)是不牵涉到页面 Web 服务器的。黑客通过各种手段将恶意脚本注入用户的页面中,比如通过网络劫持在页面传输过程中修改 HTML 页面的内容,这种劫持类型很多,有通过 WiFi 路由器劫持的和通过本地恶意软件来劫持的,它们的共同点是在 Web 资源传输过程或者在用户使用页面的过程中修改 Web 页面的数据。

DOM 型 XSS 的攻击步骤:

  1. 攻击者构造出带恶意代码的 URL;
  2. 用户打开该 URL;
  3. 浏览器接收到响应,在前端取出 URL 中的恶意代码并执行;
  4. 恶意代码窃取用户数据并发送到攻击者的网站,或冒充用户的行为,调用目标网站接口执行攻击者指定的操作。

与前两种 XSS 的区别:

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

四、XSS 的危害​

黑客窃取到 Cookie 后,就可以在其他电脑上模拟用户的登录。

2、监听用户行为​

黑客可以使用 addEventListener 接口来监听键盘事件。

3、修改 DOM​

黑客可以通过修改 DOM 伪造假的登录窗口,用来欺骗用户输入用户名和密码等信息。

五、如何防御 XSS​

1、对脚本进行过滤或转义​

最常见的做法是转义输入输出的内容,对于引号、尖括号、斜杠进行转义:

function escape(str) {
str = str.replace(/&/g, '&amp;')
str = str.replace(/</g, '&lt;')
str = str.replace(/>/g, '&gt;')
str = str.replace(/"/g, '&quto;')
str = str.replace(/'/g, '&#39;')
str = str.replace(/`/g, '&#96;')
str = str.replace(/\//g, '&#x2F;')
return str
}

对于富文本来说,会把需要的格式也过滤掉,而且考虑到要过滤的标签和标签属性太多,一般采用使用 CSP 的方式。Node.js 可通过 xss 库或 mysql2 的 escape 进行传参转译。

2、避免 innerHTML 的使用​

在使用 .innerHTML、.outerHTML、document.write() 时要特别小心,避免把不可信的数据作为 HTML 插到页面上,如果用 Vue / React,应避免使用 v-html / dangerouslySetInnerHTML 功能。

3、利用 CSP 建立白名单​

CSP 本质上就是建立白名单,指定哪些外部资源可以加载和执行。只需要配置规则,如何拦截是由浏览器自己实现的。

实施严格的 CSP 可以有效地防范 XSS 攻击,具体来讲 CSP 有如下几个功能:

  • 限制加载其他域下的资源文件;
  • 禁止向第三方域提交数据,这样用户数据也不会外泄;
  • 禁止执行内联脚本和未授权的脚本;
  • 提供了上报机制,这样可以帮助我们尽快发现有哪些 XSS 攻击,以便尽快修复问题。

可以通过两种方式来开启 CSP:

  • 设置 HTTP Header 中的 Content-Security-Policy
  • 设置 meta 标签的方式

这里以设置 HTTP Header 来举例:

3-1、只允许加载本站资源​

Content-Security-Policy: default-src 'self'

3-2、只允许加载 HTTPS 协议图片​

Content-Security-Policy: img-src https://*

3-3、允许加载任何来源框架​

Content-Security-Policy: child-src 'none'

更多 Content-Security-Policy 设置请点击

这是预防 XSS 攻击窃取用户 Cookie 最有效的防御手段。

Web 应用程序在设置 Cookie 时,将其属性设为 HttpOnly,就可以避免该网页的 Cookie 被客户端恶意 JavaScript 窃取,保护用户 Cookie 信息。

React DOM 在渲染所有输入内容之前,默认会进行转义。它可以确保在你的应用中,永远不会注入那些并非自己明确编写的内容。所有的内容在渲染之前都被转换成了字符串。这样可以有效地防止 XSS 攻击。