同源策略(SOP)限制了应用程序之间的信息共享,并且仅允许在托管应用程序的域内共享。这有效防止了系统机密信息的泄露。但与此同时,也带来了另外的问题。随着Web应用程序和微服务使用的日益增长,出于实用目的往往需要将信息从一个子域传递到另一个子域,或者在不同域之间进行传递(例如将访问令牌和会话标识符,传递给另一个应用程序)。
为了允许跨域通信,开发人员必须使用不同的技术来绕过SOP并传递敏感信息,以至于现今也成为了一个棘手的安全问题。因此,为了在不影响应用程序安全状态的情况下实现信息共享,在HTML5中引入了跨源资源共享(CORS)。但问题也随之而来,许多人为了方便干脆直接使用默认的配置,或是由于缺乏对此的了解而导致了错误的配置。
因此,作为安全分析师/工程师,了解如何利用错误配置的CORS标头非常重要。这也将有助于你在灾难发生之前更好地对其进行补救。
什么是 CORS?
CORS是一个W3C标准,全称是"跨域资源共享"(Cross-origin resource sharing)。它允许浏览器向跨源(协议 + 域名 + 端口)服务器,发出XMLHttpRequest请求,从而克服了AJAX只能同源使用的限制。
CORS需要浏览器和服务器同时支持。它的通信过程,都是浏览器自动完成,不需要用户参与。对于开发者来说,CORS通信与同源的AJAX通信没有差别,代码完全一样。浏览器一旦发现AJAX请求跨源,就会自动添加一些附加的头信息,有时还会多出一次附加的请求,但用户不会有感觉。
因此,实现CORS通信的关键是服务器。只要服务器实现了CORS接口,就可以跨源通信。
关键 CORS 标头
有许多与CORS相关的HTTP标头,但以下三个响应标头对于安全性最为重要:
Access-Control-Allow-Origin:指定哪些域可以访问域资源。例如,如果requester.com想要访问provider.com的资源,那么开发人员可以使用此标头安全地授予requester.com对provider.com资源的访问权限。
Access-Control-Allow-Credentials:指定浏览器是否将使用请求发送cookie。仅当allow-credentials标头设置为true时,才会发送Cookie。
Access-Control-Allow-Methods:指定可以使用哪些HTTP请求方法(GET,PUT,DELETE等)来访问资源。此标头允许开发人员通过在requester.com请求访问provider.com的资源时,指定哪些方法有效来进一步增强安全性。
三个攻击场景
利用CORS标头中错误配置的通配符(*)
最常见的CORS配置错误之一是错误地使用诸如(*)之类的通配符,允许域请求资源。这通常设置为默认值,这意味着任何域都可以访问此站点上的资源。例如:
GET /api/userinfo.php
Host: www.victim.com
Origin: www.victim.com
当你发送上述请求时,你将获得具有Access-Control-Allow-Origin标头设置的响应。请参阅以下响应代码。
HTTP/1.0 200 OK
Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true
在此示例中,标头配置了通配符(*)。 这意味着任何域都可以访问资源。
在测试我们客户的Web应用程序时,我们注意到了这种错误配置。我们能够利用它来获取用户信息,如姓名,用户ID,电子邮件ID,并能够将此信息发送到外部服务器。在下图中,我们将REQUEST Origin从受害者域修改为攻击者域。
以下是我们收到的响应,这意味着受害域允许访问来自所有站点的资源。我们的攻击案例中的Testing.aaa.com网站。
由于该站点共享来自任何站点的信息,因此让我们进一步的使用我们自己的域来利用它。我们创建了名为https://testing.aaa.com的域,并将其嵌入漏洞利用代码,以便从易受攻击的应用程序中窃取机密信息。当受害者在浏览器中打开https://testing.aaa.com时,它会检索敏感信息并发送给攻击者的服务器。以下是我们可以收集到的信息,如下图所示。
将信任域通配符作为 Origin
另一种常见的错误配置是允许与部分验证的域名共享信息。例如,以下请求:
GET /api/userinfo.php
Host: provider.com
Origin: requester.com
响应如下:
HTTP/1.0 200 OK
Access-Control-Allow-Origin: requester.com
Access-Control-Allow-Credentials: true
考虑一下开发人员是否配置了CORS来验证“Origin header”URL,白名单域只是“requester.com”。现在,当攻击者发起如下请求时:
GET /api/userinfo.php
Host: example.com
Connection: close
Origin: attackerrequester.com
服务器会响应:
HTTP/1.0 200 OK
Access-Control-Allow-Origin: attackerrequester.com
Access-Control-Allow-Credentials: true
发生这种情况的原因可能是后端配置错误,例如:
if ($_SERVER['HTTP_HOST'] == '*requester.com')
{
//Access data
else{ // unauthorized access}
}
我们在客户的一个应用程序中遇到了这个问题。主机域“provider.com”信任以主机名“requester.com”结尾的所有来源,例如“attackerrequester.com”。 因此,我们将origin头部篡改为attackerrequester.com并继续执行请求。
在以下响应中,相同的origin在响应Access-control-Allow-Origin标头中,这意味着provider.com域允许共享资源到以requester.com结尾的域。
因此,我们可以创建一个由列入白名单的域名组成的新域名。然后,将恶意站点嵌入利用代码从而获取受害者站点上的敏感信息。
使用 XSS 实现 CORS 的利用
开发人员用于对抗CORS利用的一种防御机制,是将频繁请求访问信息的域列入白名单。但这并不完全安全,因为只要白名单域中的一个子域易受到其他攻击(如XSS),那么也可以进行CORS利用。
让我们看一个示例,以下代码将允许requester.com的子域访问provider.com的资源配置。
if ($_SERVER['HTTP_HOST'] == '*.requester.com')
{
//Access data
else{ // unauthorized access}
}
假设用户可以访问sub.requester.com而不是requester.com,并且sub.requster.com易受XSS攻击。那么用户就可以使用XSS来利用provider.com。
我们在同一个域上托管了两个应用程序。CORS应用程序托管在testingcors.com上,另一个应用程序则托管在pavan.testingcors.com上,该应用程序易受XSS的攻击。
使用这个易受攻击的XSS子域,我们可以从testingcors.com上获取敏感信息。我们在“Name”参数中注入了恶意javascript payload。页面加载后,脚本将被执行,并从testingcors.com中获取敏感信息。
总结
CORS是上榜OWASP TOP 10的安全漏洞。在实现站点之间信息共享的过程中,人们往往会忽略CORS配置的重要性。作为开发人员或安全专家,了解此漏洞以及如何对它进行利用至关重要。
*参考来源:we45,FB小编secist编译,转载请注明来自FreeBuf.COM