常见web安全漏洞详解(一):XSS

1,613 阅读5分钟

这是我参与8月更文挑战的第27天,活动详情查看:8月更文挑战

前言

跨站脚本攻击(Cross-site scripting)是一种常见的web漏洞,英文缩写为了不与层叠样式表CSS冲突便称为XSS

XSS攻击的原理是攻击者往页面里插入恶意脚本代码,当用户浏览网页时,嵌入到其中恶意代码便被执行,从而达到盗取用户信息或其他侵犯用户安全隐私的目的。

虽然XSS的攻击方式千变万化,但可以大致分为3类:持久型、反射型、DOM 型。

image.png

持久型

持久型XSS又称存储型XSS,顾名思义,XSS攻击代码被存储在服务端数据库中,当服务器收到相应请求时,XSS攻击代码被嵌入到资源文件中作为响应发送给客户端,从而发动攻击。

image.png

以喜马拉雅FM曾经的一次XSS漏洞为例,在编辑专辑名称时,没有对专辑名进行转义过滤就保存到服务器,如果保存的专辑名是一段以<script>...</script>包裹的恶意脚本,那么当用户打开相关网页时,恶意代码作为页面源代码的一部分被浏览器解析执行,攻击达成。

反射型

反射型XSS又称非持久型 XSS,当用户点击一个恶意链接、提交一个表单或者进入一个恶意网站时,恶意代码便会和正常返回数据一起作为响应发送到受害者的浏览器,从而骗过了浏览器,使之误以为恶意脚本来自于可信的服务器,以至于让恶意脚本得以执行。

原理

攻击者诱导用户访问一个带有恶意代码的 URL 后,服务器端接收数据后处理,然后把带有恶意代码的数据发送到浏览器端,浏览器端解析这段带有 XSS 代码的数据后当做脚本执行,最终完成 XSS 攻击,这个过程就像一次反射,故称为 反射型 XSS 。

攻击步骤

  1. 攻击者构造出特殊的 URL ,其中包含恶意代码。
  2. 用户被诱导打开带有恶意代码的 URL ,服务器端将恶意代码从 URL 中取出当做参数处理,然后返回给用户带有恶意代码的数据。
  3. 用户浏览器接收到响应解析执行,混在其中的恶意代码也被执行。
  4. 恶意代码窃取用户敏感数据发送给攻击者,或者冒充用户的行为,调用目标网站接口执行攻击者指定的操作。

DOM型

基于DOM型的XSS攻击完全在浏览器上进行,与服务器无关,当页面需要使用用户输入来创建DOM元素时,就有可能受到XSS攻击。

以当前编辑器为例,当我们使用![]()语法插入图片时,编辑器会使用我们输入的图片URL来创建一个img元素,这时,我们可以通过这个特性来发起DOMXSS攻击。

首先构建一段markdown攻击代码:

![img](#"onerror="alert('这是一次xss攻击'))

#"onerror="alert('这是一次xss攻击')会被编辑器作为图片URL,插入到imgsrc属性中,由于html中属性由一对双引号包裹,因此构建出来的img标签是这样的:

<img src="#" onerror="alert('这是一次xss攻击')" alt="img">

理论上,这时会弹出一个警示栏,如下所示:

image.png

然而,由于编辑器会对URL进行了转义,将双引号、尖括号等字符转义成了16进制码值,攻击无效。由此看出,对用户输入进行转义处理是防御XSS攻击的重要手段。

image.png

上面的攻击代码只是破坏了页面结构,我们还可以通过拼接URL创建一个script标签来发动更高级的攻击来窃取cookies等,并且由于编辑器是在线保存的,攻击代码还会被存储到服务器,如果服务器没有防御措施,一旦文章发布,所有浏览文章的用户都会受到攻击,这就变成了持久型XSS

防御

为了防御XSS攻击,需要前后端共同努力:

  1. 前端在渲染页面 DOM 的时候应该选择不相信任何后端数据,任何字段都需要做转义处理。
  2. 前端对于需要即时转换成DOM的用户输入,要进行转义处理,尤其是富文本的处理。
  3. 后端在入库前应该选择不相信任何前端数据,将所有的字段统一进行转义处理。
  4. 后端在输出给前端数据统一进行转义处理。
  5. 严格管理 cookie 的读写权限,例如设置cookiehttp-only属性。

总结

对于前端,用户的输入和是永远不可信任的,对于后端,前端的输入也是永远不可信任的,否则,攻击者可以利用这个漏洞在网站上注入恶意代码,从而窃取用户的一些权限信息(cookie,session tokens)或者对网站结构进行破坏。通过前后端双重验证,可以防护绝大部分XSS攻击。