跨站点脚本攻击指南。XSS攻击原理以及如何预防XSS攻击。
什么是XSS
XSS是我们用来定义一种特殊类型的攻击的术语,在这种攻击中,由于用户输入的不安全处理,一个网站(您的网站,如果您不注意的话)可能被用作攻击其用户的载体。
基本上,一个糟糕的参与者(攻击者)可以通过某种方式将JavaScript注入到我们的站点中,利用我们在代码中留下的漏洞。
利用这个漏洞,他们可以窃取用户的信息。
基于如何利用XSS漏洞,我们有三种主要的XSS攻击:
XSS攻击危险性
假设你有一个网站。攻击者可以以某种方式注入由您的网站提供服务的JavaScript代码,然后由您的用户的浏览器执行。
这是非常危险的。
由于您在修复XSS漏洞时的疏忽,您的站点可能被用作攻击载体,您的用户信息处于危险之中。
特别是,当任何人可以在页面中注入JavaScript时,他们可以访问与网站相关的用户cookie,并读取其中包含的任何信息。并将其发送到他们自己的服务器。它们可以监听键盘事件,并访问用户在页面中键入的任何人,然后使用fetch或XHR将其发送到攻击者的服务器。例如,用户名和密码。他们还可以操纵DOM,使用这种能力,他们可以执行很多不好的事情。
XSS是前端问题还是后端问题?
全部,这是一个涉及前端和后端的网站架构问题。
XSS攻击的例子
当您允许用户输入信息时,XSS基本上是启用的,您将信息存储在(后端)然后显示回来。
假设您有一个博客,并且允许用户在该博客中发表评论。如果您盲目地接受用户输入的任何内容,恶意用户可以尝试输入JavaScript代码片段,其最基本的形式包含在中。例如<script> alert(‘前端教程网’)> </script>。
您可以将此注释存储在数据库中,并且当页面重新加载时(同样,如果没有任何预防措施),所有加载该页面的用户都将运行该JavaScript片段。
我使用了一个简单的alert()调用来做一个示例,但是正如上面所列出的,用户可以输入任何类型的脚本。
持久型XSS
持久型XSS是我们三种XSS攻击之一。
在这种情况下,漏洞的代码存储在数据库中或其他由您自己托管的源中。
一旦有人可以输入JavaScript代码片段,它就会自动由您的站点提供服务,而不需要执行任何其他操作。
反射型XSS
反射型XSS是一种通过向终端用户提供包含脚本的链接来动态利用站点中的漏洞的方法。
通过这种方式,攻击者提供了一个类似于的链接。
yoursite.com/?example=<script>alert('test')</script>
如果您的站点使用示例GET变量来执行某些操作并将其显示在页面上,并且您没有检查和清理其值,那么现在该脚本将由用户的浏览器执行。
一个典型的例子是搜索表单。它可能位于/search URL中,您可能使用GET term变量接受搜索项。
当有人搜索字符串时,您可能会显示它。现在,如果您没有对值进行清理,就会出现问题。
垃圾邮件/钓鱼邮件是这种跨站攻击的常见媒介。当然,网站越大越重要,黑客入侵的频率就越高。
DOM XSS
使用持久型XSS时,攻击代码必须被发送到服务器,在那里可以进行清理。对于反射型XSS,情况也是如此。
基于dom的XSS是一种不会将恶意代码发送到服务器的XSS。这种情况通常是通过使用URL的片段部分,或者通过引用document.URL/document.location.href来实现的。你在网上找到的一些例子已经不再适用了,因为现代浏览器会自动为我们在地址栏中转义JS。它们只有在你解除它的时候才会起作用,这有点可怕(不要这样做!)
下面是一个简单的工作示例。假设您有一个页面正在收听http://127.0.0.1:8081/testxss.html。你的客户端JavaScript会查看在URL片段部分传递的测试变量:
http://127.0.0.1:8081/testxss.html#test=something
test=something值永远不会发送到服务器。这是唯一的地方。持久/反射XSS将无法工作。但是假设您的脚本使用以下命令访问该值:
const pos = document.URL.indexOf("test=") + 5;
const value = document.URL.substring(document.URL.indexOf("test=") + 5, document.URL.length)
你直接把它写进DOM里:
document.write(value)
一切正常,直到有人这样调用URL:
http://127.0.0.1:8081/testxss.html#test=<script>alert('test')
现在,多亏了通过引用文档自动转义。在这种特殊情况下,不应该发生任何事情。
你会得到:
%3Cscript%3Ealert('x')%3C/script%3E
打印到页面。该值已转义,因此不解释为HTML。
但如果由于某种原因,您取消了文档的转义。URL值,您现在有一个问题,因为JavaScript正在运行。任何JS都可以在你的用户浏览器上运行。
在旧的浏览器上,这是一个更大的问题,因为他们没有自动转义JS放入地址栏。
静态站点容易受到跨站攻击吗?
是的!任何类型的网站,实际上。因为静态并不意味着没有从其他来源加载的信息。例如,即使没有数据库,您也可以滚动自己的表单或注释。
或者,我们可能有一个从HTTP GET或POST变量接受输入的搜索功能。没有数据库并不能使您免疫所有攻击。
如何预防XSS攻击
我们可以使用三种技术来预防:
- encoding (编码)
- validation (验证)
- CSP
编码是用来转义数据的。这样做,浏览器将不会解释JavaScript,因为,例如
<script> 将会被转换成%3Cscript%3E.
编码,作为一般规则,应该始终进行。
服务器端框架通常提供帮助函数来为您提供此功能。
在客户端JavaScript中,我们根据用例使用不同的编码机制。
如果需要向HTML元素添加内容,最好的方法是使用textContent属性将用户生成的输入分配给该元素。浏览器将为你做所有的转义:
document.querySelector('#myElement').textContent = theUserGeneratedInput
如果需要创建元素,请使用document.createTextNode():
const el = document.createTextNode(theUserGeneratedInput)
如果需要向HTML属性添加内容,请使用元素的setAttribute()方法:
document.querySelector('#myElement').setAttribute('attributeName', theUserGeneratedInput)
如果需要向URL添加内容,请使用window.encodeURIComponent()函数:
window.location.href = window.location.href + '?test=' + window.encodeURIComponent(theUserGeneratedInput)
验证通常是在无法使用转义来过滤输入时完成的。一个常见的例子是CMS,它允许用户用HTML定义页面的内容。
您可以使用黑名单或白名单策略进行验证。不同之处在于,在黑名单中,您可以决定不允许哪些标记。使用白名单,您可以决定允许哪些标记。白名单更安全,因为黑名单容易出现错误,复杂,也不具有未来保障。
CSP是指内容安全策略。这是一个由浏览器实现的新标准,它只强制执行来自安全和受信任源的JavaScript代码,并且您可以不允许在代码中运行内联JavaScript。例如,允许上述XSS利用的JavaScript类型。
通过在服务页面时添加内容安全策略HTTP头,Web服务器启用了CSP。