本博文翻译自:
https://dotnetcoretutorials.com/2017/10/25/owasp-top-10-asp-net-core-cross-site-scripting-xss/
在这篇文章的前几次迭代中,我用了一个很长的篇幅解释了什么是跨站脚本(XSS)。但在花了好几个小时来完善它之后,我觉得向你展示一个简单的屏幕截图就更容易了。
这例子很简单。我有一个用户的“搜索”页面,并且他们输入的任何查询都以“搜索查询”的形式回传给他们。代码如下所示:
因此,我们要把用户搜索的东西(或者输入用来查询的字符串),直接放到页面上。这样用户就可以输入脚本标签,或者任何他们想要的东西。这本质上是XSS的核心。获取未经验证的用户输入,并在网页上批量显示。
在这篇文章中,我将引用“我之前编写的代码”。这个代码在Github上,如果你想看一下,自己测试一下XSS。你可以在这里下载。
什么是XSS?
XSS是指跨站脚本攻击它能让攻击者将客户端脚本(通常为JavaScript,尽管可能有其他类型的注入)注入到网页上,然后再向其他用户显示。通常这些脚本试图窃取私人数据(例如cookies或浏览器存储),重定向浏览器,或者有时甚至欺骗用户进行他们通常不会做的动作。
XSS通常被定义为两种不同的类型:
反射性XSS
反射性XSS是指在用户输入结果时立即发生跨站点脚本攻击。例如,当用户搜索时,该搜索查询就会立即显示在页面上。通常,XSS的危险来自于将链接发送给不知情的用户,而用户看到的是全出乎意料的页面。
存储式XSS
存储式XSS是指把恶意脚本存储到被攻击者的网站的数据库。其他人访问数据库中的恶意脚本代码后,浏览器执行恶意脚本,被攻击。如果我们使用一个博客的例子,接受评论文章。如果您能够在博客评论中存储XSS漏洞,那么从那时起查看该博客文章的所有人都将受到影响。很明显,这有可能比反射性XSS漏洞要大得多,因为它不依赖于用户发送一个不可靠的链接,也不需要在他们的部分做任何额外的事情。
有人可以用XSS做什么?
使用Javascript
当然,要是能够在网页上注入脚本标签。世界真的是攻击者砧板上的肉。他们可以做一些简单的事情,比如将用户重定向到不同的页面(然后他们窃取用户的凭证),他们可以在页面上插入javascript来构建一个虚假的登录表单(然后他们窃取用户的凭证),或者他们甚至可以用它来盗取用户的登录cookie(然后他们窃取用户的凭证)。这可能是毁灭性的。
虽然在页面上注入javascript完全是毁灭性的,但是保护你的站点不仅仅是不允许在任何地方提交“script”这个词。实际上,你可以在没有CSS的情况下做一些相当危险的事情。
CSS
通过向页面中注入样式,攻击者可以改变页面的整个布局来欺骗用户做他们不想做的事情。我之前看到的一个“巧妙”漏洞是攻击者重新设计了一个页面,通过移动删除按钮并更改文本(现在可以添加CSS中的“内容”)来欺骗用户删除自己的帐户。
单独使用CSS,你几乎可以重写整个网站。让我们快速浏览一下我早期使用的网站。(再次,你可以在这里获得Github上的源代码)。默认情况下,它看起来有点像这样:
现在让我们尝试。让我们尝试在这里注入以下CSS负载:
所以这个URL看起来像这样:
看这个URL:
IFrames
注入iframe也是一种XSS漏洞,它可以在相当长的一段时间内不被发现,因为它对终端用户基本上是不可见的。ifram可以是“无害的”,当人们试图在他们自己的网站上建立视图时,视图里面包含了付费的广告,这是一种有害的东西,就像把一个虚假的登录表单写进页面一样。
用户输出HTML编码
现在,如果你一直在看我的示例代码,你可能会注意到一些事情。我正在谈论这个 。我想承认,我作弊了。默认情况下,当ASP.net Core Razor 将值输出到页面上时,它总是对它们进行编码。如果我们删除这个原始标签助手,并尝试注入一个脚本标签,我们可以在页面上看到:
那么,为什么没有真正运行脚本标签?它看起来应该是对的?让我们来看看页面的源代码。
看看我们的脚本标签是如何被写入HTML的。它已经被我们转义了,这意味着脚本标记还没有被实际运行!很棒!因此,对于直接写入页面的内容,实际上我们有受到框架的保护。
我们正在展示这些数据的其他地方呢?也许我们正在构建一个SPA,而不是使用ASP.net Core Razor。每个JavaScript库(甚至jQuery)都会为您编码数据。但是检查这是一个自动还是手动的过程是值得的,并且将用户输入直接输出到HTML中的任何地方都应该进行三重检查以获得有效的编码。
值得注意的一个有趣的观点是,我遇到了一些开发人员,他们坚持HTML编码,因为他们存储在数据库中,然后在网页上显示它们(通常,你不使用Razor,所以你没有得到自动编码)。这将起作用,但我认为这是一个不好的做法。当您仅在存储数据时对数据进行编码时,您就会对反射性XSS攻击保持开放,因为这些数据从未存储在任何地方(直接显示给用户)。
用户输入址编码
在将用户数据直接输出到HTML中时,HTML编码很好。但有时您可能需要接受用户输入并将其放入URL中。URL不会使用与HTML相同的字符进行编码,因此您可能会发现自己试图用Raw标签助手来覆盖所有内容。不要这样做!因为.NET core 已经覆盖了URL编码。
要访问它,首先需要在Visual Studio的软件包管理器控制台中安装以下nuget软件包:
然后,您可以像这样在视图中编码您的URL:
浏览器保护
需要注意的一点是,浏览器正在跳入,以保护用户免受XSS攻击。 在Chrome中,使用这个非常简单的负载 ,我最终得到了以下结果:
说到这个,你基本在这里可以找到一个试图绕过Chrome的XSS过滤器的用户写的好文章用户试图绕过Chrome的XSS过滤器可以在这里找到一个很好的写作https://blog.securitee.org/?p=37。从本质上讲,这将是一场军备竞赛,依靠浏览器来保护你的用户将是非常困难的。更不用说那些不更新浏览器的用户了。
X-XSS-Protection头
这是另一种保护你的用户的方法,“很好,但是请编码你的输出。”。使用X-XSS-Protection头文件,您可以指导浏览器如何最好地处理它检测到的任何XSS漏洞。标题有4个不同的值,您可以使用。
X-XSS-Protection: 0
试图在浏览器中禁用XSS保护(如果你想尝试和测试的话,这是很好的选择)。
X-XSS-Protection: 1
启用XSS保护,但如果检测到XSS,则会尝试清理输出(例如对其进行编码或去除字符)。这样做可能很危险,因为生成的HTML可能同样危险。看到这里:http://blog.innerht.ml/the-misunderstood-x-xss-protection/。
X-XSS-Protection: 1; mode=block
启用XSS保护,并在检测到任何XSS漏洞的情况下阻止加载页面。
X-XSS-Protection: 1; report=
这是一个chromium内核的头文件,它允许您向您报告任何在XSS攻击中被检测到的URL。
实际上,你应该使用的唯一选项是阻止,因为这将保护你的最佳状态。您可以在代码或服务器级别设置标题。对于代码级别,它和在管道中添加额外的中间件一样简单。类似这样:
如果您有兴趣进一步阅读,我们有一篇专门讨论X-XSS-Protection header的文章,另外还有一篇关于
每个站点都应该有的3个安全标题.。
总结
跨站脚本攻击是那些拒绝死亡的攻击之一,主要是因为人们没有做基本的事情。正如我们所看到的,在ASP.net Core中,我们的razor 标签助手是一个保护我们非常好的的解决方案,事实上,框架解决我们的大部分问题,事实上都是HTML编码。浏览器在保护人们方面也正在取得重大进展,但这并不意味着开发者能对自己在保护终端用户方面的角色感到自满。
领取专属 10元无门槛券
私享最新 技术干货