前端安全之xss攻击

463 阅读5分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第21天,点击查看活动详情

什么是XSS攻击

跨网站指令码(英语:Cross-site scripting,通常简称为:XSS)是一种网站应用程式的安全漏洞攻击,是代码注入的一种。它允许恶意使用者将程式码注入到网页上,其他使用者在观看网页时就会受到影响。这类攻击通常包含了 HTML 以及使用者端脚本语言。

  • XSS 简单点来说,就是攻击者想尽一切办法将可以执行的代码注入到网页中。

总的来说XSS 可以分为两类:持久型和非持久型。也分为三种:存储型、反射型和 DOM-based。下面来具体看一下:

1. 存储型

  • 存储型的XSS攻击也是持久型的。也就是攻击的代码被服务端写入进数据库中。
  • 具体操作:攻击者事先将恶意代码上传或者储存到漏洞服务器中,只要受害者浏览包含此恶意代码的页面就会执行恶意代码。
  • 出现场景:一般出现在网站留言、评论、博客日志等交互处,可以将恶意脚本存储到客户端或者服务端的数据库中。
  • 危害性:很大,访问了这个页面的访客,都有可能会执行这段恶意脚本。当网站访问量很大的话,就会导致大量正常访问页面的用户都受到攻击。

示例:比如在评论中注入代码

image-20220422222949635.png

非持久型相比于前者危害就小的多了,一般通过修改 URL 参数的方式加入攻击代码,诱导用户访问链接从而进行攻击。

2. 反射性

  • 又称非持久型XSS,这种攻击方式往往具有一次性,只在用户单击时触发。跨站代码一般存在链接中,当受害者请求这样的链接时,跨站代码经过服务端反射回来,这类跨站的代码通常不存储服务端。
  • 具体操作:1. 反射型XSS攻击一般是攻击者通过特定手法,诱使用户去访问一个包含恶意代码的URL。2. 用户点击了该链接的时候,3. 服务器返回HTML文档,此时该文档已经包含了那个恶意字符串, 4. 客户端就会执行了植入的恶意脚本,XSS攻击就发生
  • 出现场景:网站的搜索栏、用户登录口等地方,常用来窃取客户端Cookies或进行钓鱼欺骗。

3. DOM-based型

  • 客户端的脚本程序可以动态地检查和修改页面内容,而不依赖于服务器端的数据。DOM型xss和别的xss最大的区别就是它不经过服务器,仅仅是通过网页本身的JavaScript进行渲染触发的。
  • 具体操作:例如客户端如从URL中提取数据并在本地执行,如果用户在客户端输入的数据包含了恶意的JavaScript脚本,而这些脚本没有经过适当的过滤或者消毒,那么应用程序就可能受到DOM-based型XSS攻击。
  • 出现场景:DOM中使用了用户输入源document.URL、location.hash、location.search、document.referrer等

示例:dom中动态加载url上的参数

<!-- http://www.domain.com?name=<script>alert(1)</script> -->
<div>{{name}}</div>  

对于这种攻击方式来说,如果用户使用 Chrome 这类浏览器的话,浏览器就能自动帮助用户防御攻击。但是我们不能因此就不防御此类攻击了,因为我不能确保用户都使用了该类浏览器。

两者的攻击方式没有什么不同,都是通过电子邮件等方式发送这个含有我们构造的payload的URL给目标用户,当目标用户访可该链接时,服务器接收该目标用户的请求并进行处理,然后服务器把带有XSS代码的数据发送给目标用户的测览器,浏览器解析这段帯有XSS代码的恶意脚本后,就会触发XSS漏洞,一般用于获取对方cookies值

如何防范

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
}

通过转义可以将攻击代码 <script>alert(1)</script> 变成

// -> &lt;script&gt;alert(1)&lt;&##x2F;script&gt;
escape('<script>alert(1)</script>')

对于显示富文本来说,不能通过上面的办法来转义所有字符,因为这样会把需要的格式也过滤掉。这种情况通常采用白名单过滤的办法,当然也可以通过黑名单过滤,但是考虑到需要过滤的标签和标签属性实在太多,更加推荐使用白名单的方式

var xss = require("xss");
var html = xss('<h1 id="title">XSS Demo</h1><script>alert("xss");</script>');
// -> <h1>XSS Demo</h1>&lt;script&gt;alert("xss");&lt;/script&gt;
console.log(html);

以上示例使用了 js-xss来实现。可以看到在输出中保留了 h1 标签且过滤了 script 标签

2. CSP

CSP 本质上就是建立白名单,开发者明确告诉浏览器哪些外部资源可以加载和执行。我们只需要配置规则,如何拦截是由浏览器自己实现的。我们可以通过这种方式来尽量减少 XSS 攻击。

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

  • 设置 HTTP Header 中的 Content-Security-Policy
  • 设置 meta 标签的方式 <meta http-equiv="Content-Security-Policy">

以设置 HTTP Header 来举例:

  • 只允许加载本站资源
Content-Security-Policy: default-src 'self'
  • 只允许加载https协议图片
Content-Security-Policy: img-src https://*
  • 允许加载任何来源框架
Content-Security-Policy: child-src 'none'

对于这种方式来说,只要开发者配置了正确的规则,那么即使网站存在漏洞,攻击者也不能执行它的攻击代码,并且 CSP 的兼容性也不错。

具体其他配置文档

3. cookie 如何防范 XSS 攻击

XSS(跨站脚本攻击)是指攻击者在返回的 HTML 中嵌入 javascript 脚本,为了减轻这些 攻击,需要在 HTTP 头部配上,set-cookie

  • httpOnly 这个属性可以防止 XSS,它会禁止 javascript 脚本来访问 cookie
  • secure- 这个属性告诉浏览器仅在请求为 https 的时候发送 cookie