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 的攻击步骤:
- 黑客利用站点漏洞将一段恶意 JS 代码提交到网站的数据库中;
- 然后用户向网站请求包含了恶意 JS 脚本的页面;
- 当用户浏览该页面时,恶意脚本就会将用户的 Cookie 信息等数据上传到服务器。
存储型 XSS 的特点:
- 持久性,植入在数据库中;
- 盗取用户敏感私密信息;
- 危害面广。
2、反射型(非持久型)XSS 攻击
反射型(非持久型)XSS 漏洞(Reflected XSS),一般是通过给别人发送带有恶意脚本代码参数的 URL,当 URL 地址被打开时,特有的恶意代码参数被 HTML 解析执行。
反射型 XSS 的攻击步骤:
- 恶意 JS 脚本属于用户发送给网站请求中的一部分;
- 随后网站又把恶意 JS 脚本返回给用户;
- 恶意 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 的攻击步骤:
- 攻击者构造出带恶意代码的 URL;
- 用户打开该 URL;
- 浏览器接收到响应,在前端取出 URL 中的恶意代码并执行;
- 恶意代码窃取用户数据并发送到攻击者的网站,或冒充用户的行为,调用目标网站接口执行攻击者指定的操作。
与前两种 XSS 的区别:
DOM 型 XSS 攻击中,取出和执行恶意代码由浏览器端完成,属于前端 JS 自身的安全漏洞,而前两种 XSS 都属于服务端的安全漏洞。
四、XSS 的危害
1、窃取 Cookie 信息
黑客窃取到 Cookie 后,就可以在其他电脑上模拟用户的登录。
2、监听用户行为
黑客可以使用 addEventListener
接口来监听键盘事件。
3、修改 DOM
黑客可以通过修改 DOM 伪造假的登录窗口,用来欺骗用户输入用户名和密码等信息。
五、如何防御 XSS
1、对脚本进行过滤或转义
最常见的做法是转义输入输出的内容,对于引号、尖括号、斜杠进行转义:
function escape(str) {
str = str.replace(/&/g, '&')
str = str.replace(/</g, '<')
str = str.replace(/>/g, '>')
str = str.replace(/"/g, '&quto;')
str = str.replace(/'/g, ''')
str = str.replace(/`/g, '`')
str = str.replace(/\//g, '/')
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 设置请点击
4、使用 HttpOnly 属性防止 Cookie 被盗用
这是预防 XSS 攻击窃取用户 Cookie 最有效的防御手段。
Web 应用程序在设置 Cookie 时,将其属性设为 HttpOnly,就可以避免该网页的 Cookie 被客户端恶意 JavaScript 窃取,保护用户 Cookie 信息。
React DOM 在渲染所有输入内容之前,默认会进行转义。它可以确保在你的应用中,永远不会注入那些并非自己明确编写的内容。所有的内容在渲染之前都被转换成了字符串。这样可以有效地防止 XSS 攻击。