晴明的博客园 GitHub      CodePen      CodeWars     

[http] 同源策略 与 CORS

同源策略

如果协议端口(如果指定了一个)和名对于两个页面是相同的,则两个页面具有相同的

相对 http://store.company.com/dir/page.html 同源检测的示例:

URL 结果 原因
http://store.company.com/dir2/other.html 成功 dir2/other.html
http://store.company.com/dir/inner/another.html 成功 dir/inner/another.html
https://store.company.com/secure.html 失败 不同的协议 ( https )
http://store.company.com:81/dir/etc.html 失败 不同的端口 ( 81 )
http://news.company.com/dir/other.html 失败 不同的域名 ( news )

跨源脚本API访问

允许以下api对窗口/位置属性的跨源访问

window.blur
window.close
window.focus
window.postMessage
window.closed
window.frames
window.length
window.location
window.opener
window.parent
window.self	
window.top
window.window

location.replace
URLUtils.href

跨源网络访问

同源策略控制了不同源之间的交互

可能嵌入跨源的资源的一些示例:

<script src="..."></script>标签嵌入跨域脚本。语法错误信息只能在同源脚本中捕捉到。
<link rel="stylesheet" href="...">标签嵌入CSS。由于CSS的松散的语法规则,CSS的跨域需要一个设置正确的Content-Type报文头。不同浏览器有不同的限制。
<img>嵌入图片。支持的图片格式包括PNG,JPEG,GIF,BMP,SVG,...
<video><audio>嵌入多媒体资源。
<object>, <embed><applet>的插件。
@font-face引入的字体。一些浏览器允许跨域字体( cross-origin fonts),一些需要同源字体(same-origin fonts)。
<frame><iframe>载入的任何资源。站点可以使用X-Frame-Options报文头来阻止这种形式的跨域交互。

跨源数据存储访问

存储在浏览器中的数据,如localStorage和IndexedDB,以源进行分割。每个源都拥有自己单独的存储空间,一个源中的Javascript脚本不能对属于其它源的数据进行读写操作。

window.name属性可以用来临时存储数据,可以跨域访问。

Cookies使用不同的源定义方式。一个页面可以为本域和任何父域设置cookie,只要是父域不是公共后缀(public suffix)即可。

CORS

CORS (跨域资源共享)是一个系统, 包括传输的 HTTP headers, 其确定是否阻止或完成从该资源所在的域外的另一个域的网页上的受限资源的请求。

同源安全策略( same-origin security policy)默认禁止'跨域'请求. CORS 给予Web服务器跨域访问控制, 启用安全的跨域数据传输。

Access-Control-Allow-Origin

响应头指定了该响应的资源是否被允许与给定的origin共享。

如需允许所有资源都可以访问自己的资源:

Access-Control-Allow-Origin: *

如需允许https://www.example.com访问自己的资源:

Access-Control-Allow-Origin: https://www.example.com

如果服务器未使用*,而是指定了一个域,那么为了向客户端表明服务器的返回会根据Origin请求头而有所不同,必须在Vary响应头中包含Origin。

Access-Control-Allow-Origin: https://www.example.com
Vary: Origin

Access-Control-Allow-Credentials

响应头表示是否可以将对请求的响应暴露给页面。返回true则可以,其他值均不可以。

Access-Control-Allow-Credentials 头工作中与domxrefXMLHttpRequest.withCredentials 或 Fetch API中的Request() 构造器中的 credentials 选项结合使用。Credentials必须在前后端都被配置(即Access-Control-Allow-Credentials header 和 XHR 或Fetch request中都要配置)才能使带credentials的CORS请求成功。

使用带credentials的 XHR

var xhr = new XMLHttpRequest();
xhr.open('GET', 'http://example.com/', true); 
xhr.withCredentials = true; 
xhr.send(null);

使用带credentials的 Fetch

fetch(url, {
  credentials: 'include'  
})

Access-Control-Allow-Headers

用于 preflight request (预检请求)中,列出了将会在正式请求的 Access-Control-Expose-Headers 字段中出现的首部信息。

简单首部,如 simple headers、Accept、Accept-Language、Content-Language、Content-Type (只限于解析后的值为 application/x-www-form-urlencoded、multipart/form-data 或 text/plain 三种MIME类型(不包括参数)),它们始终是被支持的,不需要在这个首部特意列出。

如果请求中含有 Access-Control-Request-Headers 字段,那么这个首部是必要的。

Access-Control-Allow-Headers: <header-name>, <header-name>, ...

Access-Control-Allow-Headers: X-Custom-Header

Access-Control-Allow-Methods

在对 preflight request.(预检请求)的应答中明确了客户端所要访问的资源允许使用的方法或方法列表。

Access-Control-Allow-Methods: <method>, <method>, ...

Access-Control-Allow-Methods: POST, GET, OPTIONS

Access-Control-Expose-Headers

列出了哪些首部可以作为响应的一部分暴露给外部。

默认情况下,只有六种 simple response headers (简单响应首部)可以暴露给外部:

Cache-Control
Content-Language
Content-Type
Expires
Last-Modified
Pragma

如果想要让客户端可以访问到其他的首部信息,可以将它们在 Access-Control-Expose-Headers 里面列出来。

Access-Control-Expose-Headers: <header-name>, <header-name>, ...

暴露一个非简单响应首部

Access-Control-Expose-Headers: Content-Length

额外暴露自定义的首部,例如 X-Kuma-Revision,可以指定多个,用逗号隔开

Access-Control-Expose-Headers: Content-Length, X-Kuma-Revision

The Access-Control-Max-Age
表示 preflight request (预检请求)的返回结果(即 Access-Control-Allow-Methods 和Access-Control-Allow-Headers 提供的信息) 可以被缓存多久。单位是S。

将预检请求的结果缓存10分钟:

Access-Control-Max-Age: 600

Access-Control-Request-Headers

出现于 preflight request (预检请求)中,用于通知服务器在真正的请求中会采用哪些请求首部。

Access-Control-Request-Headers: <header-name>, <header-name>, ...

Access-Control-Request-Headers: X-PINGOTHER, Content-Type

Access-Control-Request-Method

出现于 preflight request (预检请求)中,用于通知服务器在真正的请求中会采用哪种 HTTP 方法。因为预检请求所使用的方法总是 OPTIONS ,与实际请求所使用的方法不一样,所以这个首部是必要的。

Access-Control-Request-Method: <method>

Access-Control-Request-Method: POST

Origin

指示了请求来自于哪个站点。该字段仅指示服务器名称,并不包含任何路径信息。该首部用于 CORS 请求或者 POST 请求。除了不包含路径信息,该字段与 Referer 首部字段相似。
有时候将该字段的值置空是有用的,例如,资源由一个 data URL 指定。

Origin: ""
# <scheme>
# 请求所使用的协议,一般是 HTTPS 协议。
# <host>
# 目的域名或 IP 地址。
# <port> 可选
# 目的 TCP 端口。缺省为服务的默认端口(对于 HTTP 请求而言,默认端口为 80)。
Origin: <scheme> "://" <host> [ ":" <port> ]

Origin: https://www.example.com

Referer

包含了当前页面的来源页面的地址,当前页面是通过此页面里的链接而进入的。Referer 首部允许服务器端识别是从哪里访问到它们的,可能会用此数据来进行统计分析、记录日志以及优化缓存策略等等。

referer 实际上是 "referrer" 误拼写。

Referer 首部拥有暴露用户的浏览历史的潜在性,涉及到用户的隐私问题。

在以下两种情况下,Referer 不会被发送:
1.来源页面采用的协议为表示本地文件的 "file" 或者 "data" URI;
2.当前请求采用的是非安全协议,而来源页面采用的是安全协议(HTTPS)。

当前页面被链接而至的前一页面的绝对路径或者相对路径。不包含 URL fragments (例如 "#section") 和 userinfo (例如 https://username:password@example.com/foo/bar/中的 "username:password" )。

Referer: <url>
posted @ 2017-08-21 19:04  晴明桑  阅读(276)  评论(0编辑  收藏  举报