Web Security 之 CORS(下)

简介: Web Security 之 CORS

内网和无凭证的 CORS

大部分 CORS 攻击都需要以下响应头的存在:

Access-Control-Allow-Credentials: true

没有这个响应头,受害者的浏览器将不会发送 cookies ,这意味着攻击者只能访问无需用户验证的内容,而这些内容直接访问目标网站就可以轻松获得。

然而,有一种情况下攻击者无法直接访问网站:网站是内网,并且是私有 IP 地址空间。内网的安全标准通常低于外网,这使得攻击者发现漏洞后可以获得进一步的访问权限。例如,某个私有网络中的跨域请求:

GET /reader?url=doc1.pdf
Host: intranet.normal-website.com
Origin: https://normal-website.com

服务器响应:

HTTP/1.1 200 OK
Access-Control-Allow-Origin: *

服务器信任所有来源的跨域请求,而且无需凭证。如果私有IP地址空间内的用户访问公共互联网,则可以从外部站点执行基于 CORS 的攻击,该站点使用受害者的浏览器作为访问内网资源的代理。

如何防护基于 CORS 的攻击

CORS 漏洞主要是由于错误的配置而产生的,因此防护措施主要也是如何进行正确配置的问题。下面将会描述一些有效的方法。

跨域请求的正确配置

如果 web 资源包含敏感信息,那么应该在 Access-Control-Allow-Origin 头中声明允许的来源。

只允许受信任的站点

Access-Control-Allow-Origin 头只能是受信任的站点。Access-Control-Allow-Origin 直接使用跨域请求的 origin 而不验证是很容易被利用的,应该避免。

白名单中避免 null

避免 Access-Control-Allow-Origin: null 。来自内部文档和沙盒请求的跨域资源调用可以指定 origin 为 null 的。CORS 头应该根据私有和公共服务器的可信来源正确定义。

避免在内部网络中使用通配符

避免在内部网络中使用通配符。当内部浏览器可以访问不受信任的外部域时,仅仅依靠网络配置来保护内部资源是不够的。

CORS 不是服务端安全策略的替代品

CORS 定义的只是浏览器行为,永远不能替代服务端对敏感数据的保护,毕竟攻击者可以直接在其它环境中伪造来自任何 origin 的请求。因此,除了正确配置的 CORS 之外,web 服务端仍然需要使用诸如身份验证和会话管理等措施对敏感数据进行保护。


Same-origin policy (SOP) - 同源策略

在本节中,我们将解释什么是同源策略以及它是如何实现的。

什么是同源策略?

同源策略是一种旨在防止网站互相攻击的 web 浏览器的安全机制。

同源策略限制一个源上的脚本访问另一个源的数据。

Origin 源由三个部分组成:schemadomainport ,所谓的同源就是要求这三个部分全部相同。 例如下面这个 URL:

http://normal-website.com/example/example.html

schema 是 http,domainnormal-website.comport 是 80 。下表显示了如果上述 URL 中的内容尝试访问其它源将会是什么情况:

访问的 URL 是否可以访问
http://normal-website.com/example/ 是,同源
http://normal-website.com/example2/ 是,同源
https://normal-website.com/example/ 否: scheme 和 port 都不同
http://en.normal-website.com/example/ 否: domain 不同
http://www.normal-website.com/example/ 否: domain 不同
http://normal-website.com:8080/example/ 否: port 不同*

*IE 浏览器将会允许访问,因为 IE 浏览器在应用同源策略时不考虑端口号。

为什么同源策略是必要的?

当浏览器从一个源发送 HTTP 请求到另一个源时,与另一个源相关的任何 cookie (包括身份验证会话cookie)也将会作为请求的一部分一起发送。这意味着响应将在用户会话中返回,并包含此特定用户的相关数据。如果没有同源策略,如果你访问了一个恶意网站,它将能够读取你 GMail 中的电子邮件、Facebook 上的私人消息等。

同源策略是如何实施的?

同源策略通常控制 JavaScript 代码对跨域加载的内容的访问。通常允许页面资源的跨域加载。例如,同源策略允许通过 <img> 标签嵌入图像,通过 <video> 标签嵌入媒体、以及通过 <script> 标签嵌入 JavaScript 。但是,页面只能加载这些外部资源,页面上的任何 JavaScript 都无法读取这些资源的内容。

同源策略也有一些例外:

  • 有些对象跨域可写入但不可读,例如 location 对象,或者来自 iframes 或新窗口的 location.href 属性。
  • 有些对象跨域可读但不可写,例如 window 对象的 length 属性和 closed 属性。
  • location 对象上可以跨域调用 replace 函数。
  • 你可以跨域调用某些函数。例如,你可以在一个新窗口上调用 closeblurfocus 函数。也可以在 iframes 和新窗口上 postMessage 函数以将消息从一个域发送到另一个域。

由于历史遗留,在处理 cookie 时,同源策略更为宽松,通常可以从站点的所有子域访问它们,即使每个子域并不满足同源的要求。你可以使用 HttpOnly 一定程度缓解这个风险。

使用 document.domain 可以放宽同源策略,这个特殊属性允许放宽特定域的同源策略,但前提是它是 FQDN(fully qualified domain name)的一部分。例如,你有一个域名 marketing.example.com,并且你想读取 example.com 域的内容。为此,两个域都需要设置 document.domainexample.com,那么同源策略将会允许这里两个域之间的访问,尽管它们并不同源。在过去,你可以将 document.domain 设置为顶级域名如 com,以允许同一个顶级域名上的任何域之间的访问,但是现代浏览器已经不允许这么做了。


CORS 和 Access-Control-Allow-Origin 响应头

在本节中,我们将解释有关 CORSAccess-Control-Allow-Origin 响应头,以及后者如何构成 CORS 实现的一部分。

CORS 通过使用一组 HTTP 头部提供了同源策略的可控制放宽,浏览器允许访问基于这些头部的跨域请求的响应。

什么是 Access-Control-Allow-Origin 响应头?

Access-Control-Allow-Origin 响应头标识了跨域请求允许的请求来源,浏览器会将 Access-Control-Allow-Origin 与请求网站 origin 进行比较,如果两者匹配则允许访问响应。

实现简单的 CORS

CORS 规范规定了 web 服务器和浏览器之间交换的头内容,其中 Access-Control-Allow-Origin 是最重要的。当网站发起跨域资源请求时,浏览器将会自动添加 Origin 头,随后服务器返回 Access-Control-Allow-Origin 响应头。

例如,origin 为 normal-website.com 的网站发起了如下跨域请求:

GET /data HTTP/1.1
Host: robust-website.com
Origin : https://normal-website.com

服务器响应:

HTTP/1.1 200 OK
...
Access-Control-Allow-Origin: https://normal-website.com

浏览器将会允许 normal-website.com 网站代码访问响应,因为 Access-Control-Allow-OriginOrigin 匹配。

Access-Control-Allow-Origin 允许多个域,或者 null ,或者通配符 * 。但是没有浏览器支持多个 origin ,且通配符的使用有限制。

带凭证的跨域资源请求

跨域资源请求的默认行为是传递请求时不会携带如 cookies 和 Authorization 头等凭证的。然而,对于带凭证的跨域请求,服务器通过设置 Access-Control-Allow-Credentials: true 响应头可以允许浏览器读取响应。例如,某个网站使用 JavaScript 去控制发起请求时一起发送 cookies :

GET /data HTTP/1.1
Host: robust-website.com
...
Origin: https://normal-website.com
Cookie: JSESSIONID=<value>

得到的响应为:

HTTP/1.1 200 OK
...
Access-Control-Allow-Origin: https://normal-website.com
Access-Control-Allow-Credentials: true

那么浏览器将会允许发起请求的网站读取响应,因为 Access-Control-Allow-Credentials 设置为了 true。否则,浏览器将不允许访问响应。

使用通配符放宽 CORS

Access-Control-Allow-Origin 头支持使用通配符 * ,如

Access-Control-Allow-Origin: *

注意:通配符不能与其他值一起使用,如下方式是非法的:

Access-Control-Allow-Origin: https://*.normal-website.com

幸运的是,基于安全考虑,通配符的使用是有限制的,你不能同时使用通配符与带凭证的跨域传输。因此,以下形式的服务器响应是不允许的:

Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true

因为这是非常危险的,这等于向所有人公开目标网站上所有经过身份验证的内容。

预检

为了保护遗留资源不受 CORS 允许的扩展请求的影响,预检也是 CORS 规范中的一部分。在某些情况下,当跨域请求包括非标准的 HTTP method 或 header 时,在进行跨域请求之前,浏览器会先发起一次 method 为 OPTIONS 的请求,并且对服务端响应的 Access-Control-* 之类的头进行初步检查,对比 origin、method 和 header 等等,这就叫预检。

例如,对使用 PUT 方法和 Special-Request-Header 自定义请求头的预检请求为:

OPTIONS /data HTTP/1.1
Host: <some website>
...
Origin: https://normal-website.com
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: Special-Request-Header

服务器可能响应:

HTTP/1.1 204 No Content
...
Access-Control-Allow-Origin: https://normal-website.com
Access-Control-Allow-Methods: PUT, POST, OPTIONS
Access-Control-Allow-Headers: Special-Request-Header
Access-Control-Allow-Credentials: true
Access-Control-Max-Age: 240

这个响应的含义:

  • Access-Control-Allow-Origin 允许的请求域。
  • Access-Control-Allow-Methods 允许的请求方法。
  • Access-Control-Allow-Headers 允许的请求头。
  • Access-Control-Allow-Credentials 允许带凭证的请求。
  • Access-Control-Max-Age 设置预检响应的最大缓存时间,通过缓存减少预检请求增加的额外的 HTTP 请求往返的开销。

CORS 能防止 CSRF 吗?


CORS 无法提供对跨站请求伪造(CSRF)攻击的防护,这是一个容易出现误解的地方。

CORS 是对同源策略的受控放宽,因此配置不当的 CORS 实际上可能会增加 CSRF 攻击的可能性或加剧其影响。

目录
相关文章
|
11天前
|
前端开发 API 数据安全/隐私保护
Web前端开发中的跨域资源共享(CORS)解决方案
【2月更文挑战第5天】在Web前端开发中,跨域资源共享(CORS)是一个常见的挑战。本文将探讨CORS的概念和原理,并介绍一些常用的解决方案,包括服务器端配置和前端处理方法,帮助开发者更好地应对跨域请求问题。
134 4
|
8月前
|
存储 安全 网络协议
Web Security 之 CSRF
Web Security 之 CSRF
30 0
|
10天前
|
存储 安全 前端开发
第五章 跨域资源共享(CORS):现代Web开发中的关键机制
第五章 跨域资源共享(CORS):现代Web开发中的关键机制
|
11天前
|
缓存 前端开发 安全
Python web框架fastapi中间件的使用,CORS跨域详解
Python web框架fastapi中间件的使用,CORS跨域详解
|
7月前
|
安全 Java Go
使用Spring Security保障你的Web应用安全
使用Spring Security保障你的Web应用安全
60 0
|
8月前
|
SQL 安全 Java
Web Security 之 Server-side template injection
Web Security 之 Server-side template injection
37 0
|
8月前
|
存储 安全 Java
Web Security 之 Insecure deserialization
Web Security 之 Insecure deserialization
23 0
|
8月前
|
存储 SQL JavaScript
Web Security 之 DOM-based vulnerabilities
Web Security 之 DOM-based vulnerabilities
67 0
|
8月前
|
缓存 安全 网络协议
Web Security 之 HTTP Host header attacks(下)
Web Security 之 HTTP Host header attacks
46 0
|
8月前
|
SQL 缓存 负载均衡
Web Security 之 HTTP Host header attacks(上)
Web Security 之 HTTP Host header attacks
290 0