01.XSS的本质
XSS是什么? 跨站脚本攻击,英文全称是Cross Site Script,为和层叠样式表区分,在安全领域称为XSS.发展到今天,由于JavaScript的强大功能和网站前端应用的复杂化,是否跨域已不再重要.
XSS的表现? XSS攻击,通常指黑客通过'脚本注入'篡改了网页,插入了恶意的脚本,从而在用户浏览网页时,控制用户浏览器的一种攻击.业界的共识:针对各种不同场景下产生的XSS,需要区别对待.
XSS的本质? XSS的本质是一种HTML注入,用户的数据被当成HTML代码的一部分来执行,从而混淆了原本的语义,产生了新的语义.
XSS的发生? 如果网站使用MVC架构,那么XSS就发生在VIEW层,即在应用拼接变量到HTML页面时产生.在有用户提交数据进行输入检查的方法,其实并不是在真正发生攻击的地方防御.
02.XSS的种类
第一种:反射型XSS
反射型XSS只是简单地把用户输入的数据"反射"给浏览器.黑客往往诱使用户点击个恶意连接,才能攻击成功.反射性XSS又称非持久性XSS攻击,它存在的时间比较短.在某个文本输入框输入JavaScript代码,用户点击才能生效:<script>alert(/xss/)</script>
第二种:存储型XSS
存储型XSS会把用户输入的数据存储在服务器端,这种XSS攻击具有很强的稳定型.常见的场景:黑客写段有恶意的JavaScript代码的博客文章,发表后,所有访问该博客文章的用户,都会在他们的浏览器中执行这段恶意的JavaScript代码.黑客把恶意的脚本保存在服务器端,这种XSS攻击就叫做存储型XSS.存储型XSS做持久型XSS,从效果上来看,它存在的时间比较长,不需要用户操作什么,只要你访问某个网址就会发生.
第三种:DOM Based XSS
效果上看是反射型XSS,因为成因特殊,所以单独列出来.通过修改页面的DOM节点形成的XSS,称为DOM Based XSS.
03.XSS的攻击
黑客能够对用户当前浏览的页面植入恶意脚本,通过恶意脚本,控制用户的浏览器.恶意脚本就是JavaScript脚本.任何JavaScript脚本可以实现的功能,恶意脚本都可以实现.
案例一:恶意脚本,通过读取浏览器的cookie对象,发起cookie劫持攻击.
因为cookie中一般加密保存当前用户的登录凭证,cookie如果丢失,意味着用户登录凭证丢失.攻击者可以不通过密码,而直接登录进用户的账户.如何处理这种情况呢?cookie的HttpOnly标识可以防止cookie劫持.
案例二:攻击者模拟GET,POST请求操作用户的浏览器,通过POST表发发消息等,类似于爬虫来获取你的邮件列表信息.
两个案例中都是在浏览器中通过JavaScript脚本自动进行的,缺少与用户交互过程.如果在提交表单时要求输入验证码,那么一般的恶意脚本都会失效.
案例三:在大多数修改用户密码的功能中,在提交新密码前,都会要求用户输入旧密码,而旧密码对于攻击者来说是不知道的.这样能限制住XSS攻击吗?答案是否定的.
为了窃取密码,攻击者可以将XSS和钓鱼相结合.实现思路是利用JavaScript在当前页上画出个伪造的登录框,当用户在登录框中输入用户名和密码后,将密码被发送到黑客的服务器上.
案例四:XSS蠕虫,是XSS攻击的终极利用形式,其破坏力和影响力是巨大的.如果是存在存储型XSS,则比较容易发起XSS蠕虫攻击.
如发送站内信,用户留言等页面,都是XSS蠕虫的高发区,需要重点关注.但页面只能由某个用户查看,比如个人材料设置,因为缺少用户间互动,即使存在XSS蠕虫,也不能用于蠕虫的传播.
攻击者想要使用XSS做坏事是很容易的,而XSS蠕虫则能够把破坏无限扩大,这是大型网站需要注意和担心的事情.
04.XSS的危害
从XSS漏洞利用角度看,存储型XSS对攻击者的用处比反射性XSS要大.因为存储型XSS在用户访问正常的URL时会自动触发.而反射性XSS会修改一个正常的URL,一般要求攻击者将XSS URL发送给用户点击,无形中提高了攻击的门槛.
05.XSS的防御
将主要精力放在如何为网站设计安全的XSS解决方案上.
5.1 HttpOnly
服务器端返回请求时处理:HttpOnly解决的是XSS后的cookie劫持攻击.因为浏览器会禁止网页的JavaScript访问带有HttpOnly属性的cookie.即可以对关键性cookie设置HttpOnly属性.需要注意,如果业务复杂,需要在所有set-cookie的位置,给关键性cookie都加上HttpOnly.如有地方漏掉,就可能会导致该方案失效.现在业界给关键业务增加HttpOnly Cookie已经成为标准做法.但是HttpOnly不是万能的,使用HttpOnly可以有效缓解XSS攻击.
5.2 输入检查
输入检查的逻辑,必须放在服务器端代码中实现.
如果只在客户端进行输入检查,很容易被攻击者绕过去.目前通过的做法是,同时在客户端和服务器端代码中进行相同的输入检查.客户端JavaScript的输入检查,可以阻挡误操作的正常用户,从而节省服务器资源.
在XSS的防御上,输入就检查一般是检查用户输入的数据是否包含一些特殊字符.比如<,>等.如果发现存在特殊字符,则需要将这些字符过滤或编码.该输入检查的方式,成为XSS Filter.
在用户提交数据时获取变量,并进行XSS检查.由于数据并没有结合渲染的HTML界面,因此XSS Filter对语境的理解并不完整.
问题一:可能会放过
比如<script src="$var"></script>
其中$var是攻击者可以控制的变量,攻击者只需要提供一个恶意脚本所在的URL地址,即可实施攻击.如果是全局性的XSS Filter,则无法看到用户数据输入的语境,只能看到用户提交的URL,可能会漏报.
问题二:可能会误杀
对于敏感字符<,如果XSS Filter不够智能,简单粗暴过滤替换<,可能会改变用户原本的意思.输入的数据,可能被展示在多个地方,每个地方的语境各不相同,如果使用单一替换操作,则会出现很多问题.
过滤器可以做精确的过滤,虽然不能智能分辨业务边界模糊的标签,但可以处理准确清晰,确定无误不允许进入数据库存储的标签内容.比如对<script>标签的过滤.
5.3 输出检查
一般来说,除了富文本的输出外,在变量输出到html页面时,可以使用转码或转义的方式来防御XSS攻击.
安全的编码函数:
针对html代码编码方式,使用HtmlEncode函数.
针对JS代码的编码方式,使用JavascriptEncode函数.
针对XML的编码方式,使用XMLEncode函数.
在'Apache Common Lang'的'StringEscapeUtils'里面,提供很多escape函数.
需要注意,编码后的数据长度可能会发生变化,而影响某些功能.
06.防御措施
XSS的本质?XSS的本质是一种HTML注入,用户的数据被当成HTML代码的一部分来执行,从而混淆了原本的语义,产生了新的语义.XSS发生在View层,在应用拼接变量到HTML页面时发生.因此用户提交数据进行输入检查的方案,属于不在发生攻击的地方进行防御.
07.风险分析
从业务风险角度看,XSS攻击的危害:
一.以用户操作来看,存储型XSS的风险会高于反射型XSS,因为存储型XSS会保存在服务器上,可能会跨页面存在.不会改变页面URL的原有结构.
二.以攻击过程来看,反射型XSS,一般要求攻击者诱导用户点击一个包含XSS代码的URL链接.存储型XSS,则只需要让用户查看一个正常的URL链接.比如WEB邮箱的邮件正文存在个存储型的XSS漏洞,当用户打开新邮件时,恶意脚本就会被执行.该隐藏的极其隐蔽,且埋伏在用户的正常业务中,风险很高.
三.从风险角度看,互动交互的页面,可能是发起XSS蠕虫.根据不同页面访问的PV数据,可以分析哪些页面受XSS攻击的影响范围.在修补XSS漏洞最大的挑战: 漏洞数量太多,开发者不愿意来不及修补问题,需要根据重要紧急程度去判断要修复的XSS漏洞.
学习整理自白帽子讲Web安全一书.