站在Java的视角,深度分析防不胜防的小偷——“XSS”

Posted Java面试那些事儿

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了站在Java的视角,深度分析防不胜防的小偷——“XSS”相关的知识,希望对你有一定的参考价值。


1F
你的网站存在XSS漏洞!

yrzx404这两天比较闲,说我们给小伙伴们来写一个用来提建议的网站吧,能让小伙伴第一时间将想要说的话反馈给我们,并且所有小伙伴都可以看到其他小伙伴提出的建议。这还不简单,就一个单页网站,再结合CRUD就可以搞定,那这么简单的任务就分配给znlover那家伙去搞吧。那znlover是如何实现这个小网站的?说来有一套,znlover采用了spring-boot+jpa+thymeleaf技术栈不到半个小时就搞定了,虽然界面简陋,但功能基本完成了,界面如下:

站在Java的视角,深度分析防不胜防的小偷——“XSS”

东哥看到这个网站后,测试了5分钟,说“你这个网站不安全,有XSS漏洞!”。XSS漏洞?一个留言板,怎么会存在漏洞,znlover十分不解。通过查看东哥的留言,发现确实网站的运行状态不正常了,现在一打开留言网站,就会弹出一个提醒框:

站在Java的视角,深度分析防不胜防的小偷——“XSS”

这是什么鬼?html就没有使用过alert函数啊,怎么会有弹框?通过数据库查询,发现东哥输入的留言是这样的:

站在Java的视角,深度分析防不胜防的小偷——“XSS”


站在Java的视角,深度分析防不胜防的小偷——“XSS”
2F
XSS漏洞攻击原理

首先我们来看一下造成XSS漏洞攻击的原因,获取留言与展示留言的前端代码如下:

站在Java的视角,深度分析防不胜防的小偷——“XSS”

站在Java的视角,深度分析防不胜防的小偷——“XSS”

可以看到,前端通过ajax向后台异步请求json数据,然后通过字符串拼接成一个table DOM的方式来实现留言显示,这是一种很常见也很常规的前后端数据交互的代码写法,在正常情况下是不会有问题的。但与SQL注入的原理本质相同,问题就出现在HTML代码与用户的输入产生了拼接,这就为恶意漏洞利用者提供了代码执行的机会。正如在上一节中,yrzx404输入的留言是一段合法的javasrcipt代码,在通过拼接后生成的的html页面,浏览器就会将其解析成可执行的javasrcipt代码进行执行,因此造成了XSS跨站脚本攻击(Cross Site Scripting),造成XSS执行拼接后的Html片段如下:

站在Java的视角,深度分析防不胜防的小偷——“XSS”

所以,XSS漏洞的执行本质上与很多漏洞的造成原因相同,都是由于“数据与代码未严格分离”,前端将用户的数据当做代码来执行了。

站在Java的视角,深度分析防不胜防的小偷——“XSS”
3F
XSS漏洞的危害

XSS漏洞是在客户端执行,如果XSS攻击发生在访问量很大的页面,那将会是很严重的安全事件。试想,如果一个门户网站被小黑客利用XSS搞了个弹框恶作剧,那将会极大的损害公司的声誉与口碑,为公司带来无形的损失。如果仅仅是恶作剧,可能只是一次是不成熟的白帽行为,想借此提醒开发者网站存在漏洞,请尽快修补。但往以获取用户数据为目的黑客,会很隐蔽地收集用户的隐私数据,cookie,详细的用户主机信息,最严重的是进行种网马。这将会使我们的用户处于极其不安全的环境中,这也是为什么XSS漏洞攻击常年在OWASP榜首的位置。这里我们来看看黑客通过XSS获取用户cookie的恶意脚本:

站在Java的视角,深度分析防不胜防的小偷——“XSS”

上面js脚本构造一个<img> DOM,并通过document.cookie获取到了用户当前会话的cookie并藏在了img标签的url中,这样该页面被浏览器加载后便会带着用户的cookie去某一服务器访问图片了。黑客只需简单搭建一个Http服务器,看访问日志即可收货偷来的cookie:

站在Java的视角,深度分析防不胜防的小偷——“XSS”

我们知道,cookie是网站服务器用于与客户端保持会话与身份认证的关键属性,一旦黑客获取到了用户cookie,往往意味着黑客同时获取到了客户当前会话的访问权利,从而可以不用登陆验证便可进入用户的系统,这太危险了!


站在Java的视角,深度分析防不胜防的小偷——“XSS”
4F
Cookie的防御HttpOnly 

为了解决XSS攻击漏洞会造成cookie被劫持攻击的问题,微软在IE 6开始支持Cookie HttpOnly标准,HttpOnly的作用是,如果在Http Response中,使用HttpOnly来标识的Cookie在浏览器中将无法被javascript访问,也就是说document.cookie就失效了。从Java EE 6.0开始,便支持通过Cookie.setHttpOnly(true)来设置HttpOnly类型的Cookie,代码如下:

站在Java的视角,深度分析防不胜防的小偷——“XSS”

此外还可以直接在WEB-INF/web.xml中将Session相关的Cookie添加HttpOnly标记,代码如下:

站在Java的视角,深度分析防不胜防的小偷——“XSS”

可以看到,我们的XSS Payload已经无法通过获取到用户的cookie了:

站在Java的视角,深度分析防不胜防的小偷——“XSS”

如今基本所有公开浏览器都对HttpOnly提供了支持,可以如此高效简单的防御一个web安全问题的手段可真不多见,真可谓四两拨千斤,但悲哀的是HttpOnly标准出现了15年了(2002年制定),但清楚知道其作用的网站开发人员却并不多。

站在Java的视角,深度分析防不胜防的小偷——“XSS”
5F
前端XSS防护

既然XSS漏洞造成原因是由于执行了用户输入数据造成的,那么最直接的防御策略就是对用户的输入进行处理,将有可能造成XSS攻击的字符进行转义,这样就可以防止恶意XSS数据在浏览器中解析成合法的JavaScript脚本来执行。这里我们将留言进行敏感字符转意。作者这里使用了一个开源的用于XSS过滤转义的javascript库 -- js-xss,其支持以npm bower的方式依赖引入,在其github主页有详细安装与使用方法介绍。js-xss库提供了一个非常简单方便的XSS过滤转义函数filterXSS(),我们直接用它来对提交的留言进行过滤处理,代码如下:

站在Java的视角,深度分析防不胜防的小偷——“XSS”

此时,我们在将XSS Payload提交测试,可以发现浏览器没有触发XSS执行,因为js脚本确实被转义了:

站在Java的视角,深度分析防不胜防的小偷——“XSS”

这里filteXSS函数将敏感的括号尖括号等字符进行了转义,因此浏览器解析时XSS Payload就失效了。此外,通过测试,用来偷Cookie的XSS Payload也同样失效了。OK,防御策略小有成效,值得庆祝,产品可以上线了!但真的没有问题了吗,这样防御真的可以解决XSS攻击吗?

站在Java的视角,深度分析防不胜防的小偷——“XSS”
6F
我们真的可以相信前端吗?

在上一节我们通过将用户的输入内容使用js-xss进行编码转义,便达到了防止用户输入恶意脚本的效果,但是我们能确保向服务器提交的数据一定是通过网站前端正常逻辑进行提交的吗?显然不能,如果黑客通过分析浏览器向服务器提交留言请求的Http数据包格式,手工构造向服务器留言的Http请求数据包,那就绕过了网站前端的XSS过滤逻辑,这里我们模仿黑客通过PostMan来向网站提交留言:

站在Java的视角,深度分析防不胜防的小偷——“XSS”

不出所料,留言提交成功了,打开网站前端,可以看到XSS Payload成功执行。

前端绕过问题,是一个具有普遍性的安全问题,这里安全不仅仅是指网络攻防安全,更多的情况是发生在业务安全中。作者曾接手过一个项目就是这样,系统中有一个类似消费转账的功能,既然是消费,那余额肯定应该是越消费越少,最起码消费金额不能是负数。网站前端对消费金额进行了数字,正负数和金额范围的校验,从而保证用户的消费金额一定是一个合法有效的数字。但是后端接收订单的接口却没有对消费金额的合法性进行判断,导致用户可以绕过前端向接口提交负数的消费金额的问题,用户的余额可以越花越多!虽然这个业务安全漏洞没有被非法利用,但是却为档次参与该项目的开发人员敲响了警钟,一切我们无法保证来源的输入,都应该校验

回归XSS防御的主题,既然我们不能依赖前端过滤,那还有必要在前端进行XSS的防御吗?作者认为,还是有必要的,一方面可以防御DOM Base类型的XSS;另一方面,从网站业务的角度来说,在前端对用户的输入进行合法性校验,可以避免合法用户误操作的问题,在一定程度减轻了服务器的请求压力。

站在Java的视角,深度分析防不胜防的小偷——“XSS”
7F
依赖Thymeleaf模板

作者在开发该网站的过程中使用了thymeleaf模板作为前端view层,那么我们一起来看看thymeleaf对于XSS的防御效果如何。这里前端不再通过ajax异步请求的方式获取历史留言,而是采用务器端渲染,直接使用ModeAndView向页面传值:

站在Java的视角,深度分析防不胜防的小偷——“XSS”

现在进行XSS攻击测试,依然使用alert XSS Payload进行留言,可以发现XSS并没有触发执行,反而被按照正常的字符串显示出来了,打开控制台,可以发现XSS被转义了:

站在Java的视角,深度分析防不胜防的小偷——“XSS”

thymeleaf模板在对th:text标签进行渲染的时候,默认对于特殊字符进行了转义处理,这很符合“Security by Default”的安全原则。但是thymeleaf同时也提供了不转义的文本标签th:utext,使用th:utext将会按照数据原有的格式进行渲染,在页面拥有XSS漏洞情况下,依然会有HTML代码拼装的问题,所以这里需要大家在开发与审计过程中要多多留意,能不使用th:utext的地方尽量不要使用,如果必须使用,也要结合具体业务综合考虑此处XSS安全防御的问题。

即便如此,作者还是认为将安全问题交由公用框架还是相对靠谱的SDL(安全开发生命周期),结合当下很多公司采用前后端完全分离的技术框架,您可能会问,如果我们没有使用模板怎么办?前端可以考虑使用angular、vue等框架来构建。总之,一个原则就是尽量依赖专家代码(虽然并不能百分百保证安全)。

站在Java的视角,深度分析防不胜防的小偷——“XSS”
8F
OWASP ESAPI企业级防护

OWASP中的ESAPI项目是专为解决web应用程序安全问题的开源项目,是由安全专家写的专家代码,很多著名公司都使用了ESAPI来为网站进行安全加固,ESAPI并不仅仅只提供了对java语言的支持,还提供了很多其他语言的版本库,但对java语言的支持是最完善的。java开发者可以很容易的将ESAPI应用入现有的项目。ESAPI Java项目大多以静态方法的方式提供接口,这里我们使用ESAPIencoder模块对留言的输入进行编码转义:

站在Java的视角,深度分析防不胜防的小偷——“XSS”

在实际项目中这样处理会存在一个问题,我们持久化的数据实际是被转义处理后的数据,并非用户的实际输入数据,会造成存储与实际输入不一致的问题,因此可以不在留言输入的接口中做编码,可以在输出接口中对留言做编码,也同样达到了防御XSS的效果,并且保证了数据的一致性。此外,ESAPI还有很多有用的解决web安全的功能,作者以后会陆续推出有关ESAPI使用的文章。

站在Java的视角,深度分析防不胜防的小偷——“XSS”
9F
关于富文本编辑器的处理

在网站的一些业务需求中,往往需要允许用户上传具有自定义样式的文本,例如广告、文章、公告等,而这些具有样式的文本就是富文本,实际上富文本就是一段HTML代码,因此浏览器可以无缝对其提供支持,为用户提供了极大的方便。但富文本的特性也使其成为了XSS攻击的重灾区,因此必须对其防范。关于富文本的XSS防范,我们不能简单的采用前文的方法将输入进行转义,否则转以后的富文本将无法被浏览器渲染。那应该这么办?

处理富文本时,要严禁对任何JavaScript事件的支持的,因为在一般情况下,富文本的展示中不应该包含JavaScript事件这种动态效果。此外我们应考虑将一些敏感标签过滤掉,例如<script>、<iframe>、<base>、<form>等不应该出现在富文本中的HTML标签。此外在富文本中对于CSS的过滤也是件很麻烦的事情,需要检查其中是否包含恶意代码。对于威胁的监测,我们需要借助Html解析来进行识别过滤,好在对于富文本的防御过滤,OWASP开源了一个非常棒的项目Anti-Samy

站在Java的视角,深度分析防不胜防的小偷——“XSS”

OWASP ESAPI中的validator模块下 HTMLValidationRule 便是直接引用了AntiSamy,因此如果项目中已近引用了ESAPI,那么可以很方便的对富文本进行过滤:

站在Java的视角,深度分析防不胜防的小偷——“XSS”



10F
 关于源码



此外关于XSS的攻击,还有很多绕过技巧,感兴趣的小伙伴可以阅读以下文章:





小结


作为抛砖引玉之文,本文并无法覆盖到了XSS防御的方方面面,意在让web开发者重视XSS漏洞的问题。具体的防护方案还需要考虑系统的方方面面,此外,本文只探讨了基于HTML页面的存储型XSS的攻击原理,XSS攻击并不仅仅只发生在html页面中,CSS、Flash等也有可能存在XSS漏洞,相对于HTML更加隐蔽,不易被发现,限于本文篇幅已经过长,剩余的内容将会在以后的文章中来展现,尽情支持和与关注。




以上是关于站在Java的视角,深度分析防不胜防的小偷——“XSS”的主要内容,如果未能解决你的问题,请参考以下文章

java 谁是小偷?

java 谁是小偷?

深入浅出Java并发编程指南「原理分析篇」站在Linux操作系统角度去看待Java的Thread(线程)机制

从JVM视角分析try...catch...性能

小偷跑了

Java零基础如何入门?给初学者的建议,带你快速入门Java