有奖捉虫:云通信与企业服务文档专题,速来> HOT

同源策略

同源策略限制从一个源加载的文档或脚本与来自另一个源的资源进行交互的方式,是用于隔离潜在恶意文件的关键安全机制。同协议、同域名(或 IP)、以及同端口视为同一个域,一个域内的脚本仅仅具有本域内的权限,即本域脚本只能读写本域内的资源,而无法访问其它域的资源。这种安全限制称为同源策略。

同源的定义

两个页面的协议、域名和端口(若指定了端口)相同,则视为同源。如下表给出了相对http://www.example.com/dir/page.html的同源检测示例:
URL
结果
原因
http://www.example.com/dir2/other.html
成功
协议、域名、端口相同
http://www.example.com/dir/inner/another.html
成功
协议、域名、端口相同
https://www.example.com/secure.html
失败
协议不同 ( HTTPS )
http://www.example.com:81/dir/etc.html
失败
端口不同 ( 81 )
http://news.example.com/dir/other.html
失败
域名不同

跨域访问

跨域资源共享(Cross-Origin Resource Sharing,CORS)机制,我们简称为跨域访问,允许 Web 应用服务器进行跨域访问控制,从而使跨域数据传输得以安全进行。CORS 需要浏览器和服务器同时支持。目前,所有浏览器都支持该功能,IE 浏览器要求版本 IE10 或以上。
整个 CORS 通信过程,都是浏览器自动完成,不需要用户参与。对于开发者来说,CORS 通信与同源的 AJAX 通信没有差别,代码完全一样。浏览器一旦发现 AJAX 请求跨源,就会自动添加一些附加的头信息,有时还会多出一次附加的请求,但用户无感知。
因此,实现 CORS 通信的关键是服务器。只要服务器实现了 CORS 接口,即可跨源通信。

CORS 主要使用场景

用户在使用浏览器的情况下会使用到 CORS,因为控制访问权限的是浏览器而非服务器。因此使用其它客户端的时候无需关心任何跨域问题。
CORS 的主要应用是实现在浏览器端使用 AJAX 直接访问 COS 的数据或上传、下载数据,而无需通过用户本身的应用服务器中转。对于同时使用 COS 和使用 AJAX 技术的网站,建议使用 CORS 来实现与 COS 的直接通信。

COS 对 CORS 的支持

COS 支持对 CORS 规则的配置,从而根据需求允许或者拒绝相应的跨域请求。该 CORS 规则配置属于存储桶级别。
CORS 请求的通过与否和 COS 的身份验证等是完全独立的,即 COS 的 CORS 规则仅仅是用来决定是否附加 CORS 相关的 Header 的一个规则。是否拦截该请求完全由浏览器决定。
目前 COS 的所有 Object 相关接口都提供了 CORS 相关的验证,另外 Multipart 相关的接口目前也已经完全支持 CORS 验证。
说明
当同一个浏览器上的分别来源于www.a.comwww.b.com的两个页面同时请求同一跨域资源时,若www.a.com的请求先到达服务器,服务器会将资源带上 Access-Control-Allow-Origin 的 Header,并返回给www.a.com的用户。这时www.b.com又发起了请求,浏览器会将 Cache 的上一次请求响应返回给用户,Header 的内容和 CORS 的要求不匹配,就会导致www.b.com请求失败。

CORS 设置示例

以下简单示例介绍使用 AJAX 从 COS 获取数据的配置步骤。示例中使用的存储桶(Bucket)权限设置为公有(Public),访问权限为私有的存储桶(Bucket)只需要在请求中附加签名,其余配置相同。 以下示例中使用的存储桶名为 corstest,存储桶访问权限为公有读私有写。

准备工作

1. 确认文件可正常访问 上传一个 test.txt 的文本文档到 corstest。test.txt 的访问地址为http://corstest-125xxxxxxx.cos.ap-beijing.myqcloud.com/test.txt。 使用 curl 直接访问该文本文档,请将以下地址替换为您的文件地址:
curl http://corstest-125xxxxxxx.cos.ap-beijing.myqcloud.com/test.txt
返回 test.txt 文件的内容:test。表示该文档可以正常访问。


2. 使用 AJAX 技术访问文件 我们现在尝试使用 AJAX 技术来直接访问该 test.txt 文件。
2.1 写一个简单的 HTML 文件,将以下代码复制到本地保存成 HTML 文件后使用浏览器打开。因为没有设置自定义的头,因此该请求不需要预检。
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
</head>
<body>
<a href="javascript:test()">Test CORS</a>
<script>
function test() {
var url = 'http://corstest-125xxxxxxx.cos.ap-beijing.myqcloud.com/test.txt';
var xhr = new XMLHttpRequest();
xhr.open('HEAD', url);
xhr.onload = function () {
var headers = xhr.getAllResponseHeaders().replace(/\\r\\n/g, '\\n');
alert('request success, CORS allow.\\n' +
'url: ' + url + '\\n' +
'status: ' + xhr.status + '\\n' +
'headers:\\n' + headers);
};
xhr.onerror = function () {
alert('request error, maybe CORS error.');
};
xhr.send();
}
</script>
</body>
</html>
2.2 在浏览器中打开该 HTML 文件,单击 Test CORS 发送请求后,出现以下错误,错误提示:无权限访问,原因是没有找到 Access-Control-Allow-Origin 这个 Header。显然,这是因为服务器没有配置 CORS。


2.3 访问失败,再进入 Header 界面检查原因,可见浏览器发送了带 Origin 的 Request,因此是一个跨域请求。


说明
我们将网页搭建在服务器上,地址为http://127.0.0.1:8081,所以 Origin 是http://127.0.0.1:8081

设置 CORS

确定访问不成功的原因之后,可以通过设置存储桶相关的 CORS 来解决以上问题。COS 控制台可以进行 CORS 设置,本示例使用控制台来完成 CORS 的设置。若您的 CORS 设置不是特别复杂,也建议使用控制台来完成 CORS 设置。
1. 登录 COS 控制台 ,单击存储桶列表,进入相关的存储桶,单击安全管理页签,下拉页面即可找到“跨域访问 CORS 设置”。
2. 单击添加规则,添加第一条规则,使用最宽松的配置如下:


注意
CORS 设置是由一条一条规则组成的,会从第一条开始逐条匹配,以最早匹配上的规则为准。

验证结果

配置完成后,重新尝试访问 test.txt 文本文件。结果如下,可以正常访问请求。



故障排除及建议

若想要排除跨域带来的访问问题,可以将 CORS 设置为以上最宽松的配置,该配置允许所有的跨域请求。该配置下依然出错,则表明错误出现在其他部分而不是 CORS。
除了最宽松的配置之外,您还可以配置更精细的控制机制来实现针对性的控制。例如,对于本示例可以使用如下最小的配置匹配成功:

因此对于大部分场景来说,推荐您根据自己的使用场景来使用最小的配置以保证安全性。

CORS 配置项说明

CORS 配置有以下几项:

来源 Origin

允许跨域请求的来源。
可以同时指定多个来源,每行只能填写一个。
配置支持*,表示全部域名都允许,不推荐。
支持单个具体域名,形如http://www.abc.com
支持二级泛域名,形如http://*.abc.com ,但是每行只能有一个*号。
注意不要遗漏协议名 HTTP 或 HTTPS,若端口不是默认的80,还需要带上端口。

操作 Methods

枚举允许的跨域请求方法(一个或者多个)。 例如:GET、PUT、POST、DELETE、HEAD。

Allow-Header

允许的跨域请求 Header。
可以同时指定多个来源,每行只能填写一个。
Header 容易遗漏,没有特殊需求的情况下,建议设置为* ,表示允许所有。
大小写不敏感。
在 Access-Control-Request-Headers 中指定的每个 Header,都必须在 Allowed-Header 中有对应项。

Expose-Header

暴露给浏览器的 Header 列表,即用户从应用程序中访问的响应头(例如一个 Javascript 的 XMLHttpRequest 对象)。
具体的配置需要根据应用的需求确定,默认推荐填写 Etag。
不允许使用通配符,大小写不敏感,每行只能填写一个。

超时 Max-Age

浏览器对特定资源的预取请求(OPTIONS 请求)返回结果的缓存时间,单位为秒。没有特殊情况时可以设置稍大一点,例如60秒,该项是可选配置项。