浏览器的同源策略####
同源策略限制从一个源加载的文档或脚本如何与来自另一个源的资源进行交互。
一个源的定义#####
如果协议,端口(如果指定了一个)和主机对于两个页面是相同的,则两个页面具有相同的源。
下表给出了相对 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 ) |
(以上信息来自于:MDN)
同源策略的本质####
跨域并非浏览器限制了发起跨站请求,而是跨站请求可以正常发起,但是返回结果被浏览器拦截了。最好的例子是CSRF跨站攻击原理,请求是发送到了后端服务器无论是否跨域!注意:有些浏览器不允许从HTTPS的域跨域访问HTTP,比如Chrome和Firefox,这些浏览器在请求还未发出的时候就会拦截请求,这是一个特例。
CORS概述####
跨源资源共享标准通过新增一系列 HTTP 头,让服务器能声明哪些来源可以通过浏览器访问该服务器上的资源。另外,对那些会对服务器数据造成破坏性影响的 HTTP 请求方法(特别是 GET 以外的 HTTP 方法,或者搭配某些MIME类型的POST请求),标准强烈要求浏览器必须先以OPTIONS请求方式发送一个预请求(preflight request),从而获知服务器端对跨源请求所支持 HTTP 方法。在确认服务器允许该跨源请求的情况下,以实际的 HTTP 请求方法发送那个真正的请求。服务器端也可以通知客户端,是不是需要随同请求一起发送信用信息(包括 Cookies 和 HTTP 认证相关数据)。
以下两种情况会发起预请求######
- 请求以 GET, HEAD 或者 POST 以外的方法发起请求。或者,使用 POST,但请求数据为 application/x-www-form-urlencoded, multipart/form-data 或者 text/plain 以外的数据类型。比如说,用 POST 发送数据类型为 application/xml 或者 text/xml 的 XML 数据的请求。
- 使用自定义请求头
注意:预请求有浏览器自动发起。
附带凭证信息的请求#####
对于跨站请求,浏览器是不会发送凭证信息的。但如果设置XMLHttpRequest. withCredentials = true
,该请求就会携带响应的cookie。服务器端的响应中,如果没有返回Access-Control-Allow-Credentials: true的响应头,那么浏览器将不会把响应结果传递给发出请求的脚本程序,以保证信息的安全。
HTTP 请求头###
这部分内容列出来当浏览器发出跨域请求时可能用到的HTTP请求头.注意这些请求头信息都是在请求服务器的时候已经为你设置好的,当开发者使用跨域的XMLHttpRequest的时候,不需要手动的设置这些头信息.
- Origin:表明发送请求或者预请求的域.
- Access-Control-Request-Method:在发出预检请求时带有这个头信息,告诉服务器在实际请求时会使用的请求方式.
- Access-Control-Request-Headers:在发出预检请求时带有这个头信息,告诉服务器在实际请求时会携带的自定义头信息.如有多个,可以用逗号分开.
HTTP 响应头###
这部分里列出了跨域资源共享(Cross-Origin Resource Sharing)时,服务器端需要返回的响应头信息.上一部分内容是这部分内容在实际运用中的一个概述.
- Access-Control-Allow-Origin:返回的资源需要有一个 Access-Control-Allow-Origin 头信息,origin参数指定一个允许向该服务器提交请求的URI.对于一个不带有credentials的请求,可以指定为'*',表示允许来自所有域的请求.
- Access-Control-Expose-Headers:设置浏览器允许访问的服务器的头信息的白名单.
- Access-Control-Max-Age:这个头告诉我们这次预请求的结果的有效期是多久.
- Access-Control-Allow-Credentials:告知客户端,当请求的credientials属性是true的时候,响应是否可以被得到.当它作为预请求的响应的一部分时,它用来告知实际的请求是否使用了credentials.注意,简单的GET请求不会预检,所以如果一个请求是为了得到一个带有credentials的资源,而响应里又没有Access-Control-Allow-Credentials头信息,那么说明这个响应被忽略了.
- Access-Control-Allow-Methods:指明资源可以被请求的方式有哪些(一个或者多个). 这个响应头信息在客户端发出预检请求的时候会被返回.
- Access-Control-Allow-Headers:也是在响应预检请求的时候使用.用来指明在实际的请求中,可以使用哪些自定义HTTP请求头.