古语云:“无规矩不成方圆”。同源策略(Same origin policy
)是一种约定,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,则浏览器的正常功能可能都会受到影响。可以说Web是构建在同源策略基础之上的,浏览器只是针对同源策略的一种实现。
一、怎样才算是同源 所谓同源是指域名(主机名或者IP地址)、端口、协议相同。不同的客户端脚本(Javascript
、ActionScript
)在没明确授权的情况下,不能读取对方的资源。
不同源的例子: 1. 域名(主机名或者IP地址)不同 http://news.company.com/index.html
与http://www.company.com/index.html
不同源,域名不同,news
子域与www
子域不同。 http://company.com/index.html
与http://www.company.com/index.html
不同源,域名不同,顶级域与www
子域不是一个概念。 2. 端口不同 http://www.company.com:8080/index.html
与 http://www.company.com/index.html
不同源,端口不同,8080
与默认的80
端口不同。 3. 协议不同 https://www.company.com/index.html
与 http://www.company.com/index.html
不同源,协议不同,https
与http
是不同协议。 同源的例子: http://www.company.com/a/c/index.html
与 http://www.company.com/b/d/index.html
属于同源,域名,端口,协议均相同。
二、IE特例 在处理同源策略的问题上,IE存在两个主要的不同之处。
1. 授权范围(Trust Zones) 两个相互之间高度互信的域名,如公司域名(corporate domains),不遵守同源策略的限制。 2. 端口 IE并没有将端口号加入到同源策略的组成部分之中,因此,https://www.company.com/index.html
与 http://www.company.com/index.html
属于同源并且不受任何限制。
这些例外都是非标准的,其他也并未作出支持
三、读写权限 Web上的资源有很多,有的只有读权限,有的同时拥有读和写的权限。比如:HTTP请求头里的Referer(表示请求来源)只可读,同源和不同源就是根据这个Referer值进行判断的, 而document.COOKIE
则具备读写权限。这样的区分也是为了安全上的考虑。
注意:COOKIE
中的同源只关注域名,忽略协议和端口。所以https://localhost:8080/
和http://localhost:8081/
的COOKIE
是共享的。
四、同源策略示例 如果是打开百度,在控制台中请求CSDN的网页的话,会报下面的异常: Chrome
中会报下面的异常:
IE
中会报下面的异常:
五、跨域访问资源1. Ajax跨域(CORS
) Ajax
主要是通过XMLHttpRequest
对象与远程的服务器进行信息交互的。但是XMLHttpRequest
受到同源策略的约束,不能跨域访问资源。 如果XMLHttpRequest
能够跨域访问资源,则会导致安全问题。因为XMLHttpRequest
是一个纯粹的Javascript
对象,如果某网站存在漏洞导致XSS
注入了Javascript
脚本,这个脚本就可以通过Ajax
获取用户的信息并通过Ajax
提交到其他站点。 但是XMLHttpRequest
可以通过访问目标域的服务器,然后目标域的服务器返回的HTTP响应头来授权是否允许跨域访问,假如目标站点http://www.foo.com
返回的响应头如下: Access-Control-Allow-Origin: http://www.evil.com
那么www.evil.com
站点上的客户端脚本就有权通过Ajax
技术对www.foo.com
上的数据进行读写操作。 请求及响应过程如下: 通过在HTTP Header
中加入扩展字段,服务器在相应网页头部加入字段表示允许访问的domain
和HTTP method
,客户端检查自己的域是否在允许列表中,决定是否处理响应。 实现的基础是Javascript
不能够操作HTTP Header
。某些浏览器插件实际上是具有这个能力的。 服务器端在HTTP
的响应头中加入(页面层次的控制模式):
Access-Control-Allow-Origin: evil.com Access-Control-Request-Method: GET, POST Access-Control-Allow-Headers: Content-Type, Authorization, Accept, Range, Origin Access-Control-Expose-Headers: Content-Range Access-Control-Max-Age: 3600
多个域名之间用逗号分隔,表示对所示域名提供跨域访问权限。”*”表示允许所有域名的跨域访问。
客户端可以有两种行为: 1. 发送OPTIONS
请求,请求Access-Control
信息。如果自己的域名在允许的访问列表中,则发送真正的请求,否则放弃请求发送。 2. 直接发送请求,然后检查response
的Access-Control
信息,如果自己的域名在允许的访问列表中,则读取response body
,否则放弃。
本质上服务端的response
内容已经到达本地,Javascript
决定是否要去读取。
Support: [Javascript Web Applications]
* IE >= 8 (需要安装caveat) * Firefox >= 3 * Safari 完全支持 * Chrome 完全支持 * Opera 不支持
CORS
协议提升了Ajax
的跨域能力,但也增加了风险。一旦网站被注入脚本或XSS
攻击,将非常方便的获取用户信息并悄悄传递出去。
2. Jsonp实现跨域访问请求(单向跨域) JSONP
(JSON with Padding
)是一个简单高效的跨域方式,HTML
中的script
标签可以加载并执行其他域的Javascript
,于是我们可以通过script
标记来动态加载其他域的资源。例如我要从域A的页面pageA
加载域B的数据,那么在域B的页面pageB
中我以Javascript
的形式声明pageA
需要的数据,然后在pageA
中用script
标签把pageB
加载进来,那么pageB
中的脚本就会得以执行。JSONP
在此基础上加入了回调函数,pageB
加载完之后会执行pageA
中定义的函数,所需要的数据会以参数的形式传递给该函数。
第一个站点的测试页面(http://localhost:8080/test.html
):
标签嵌入跨域脚本。语法错误信息只能在同源脚本中捕捉到 b.
标签嵌入CSS
。 c.
嵌入图片。支持的图片格式包括PNG
,JPEG
,GIF
,BMP
,SVG
,… d.
和
嵌入多媒体资源。 e.
,
和
的插件。 f.@font-face
引入的字体。一些浏览器允许跨域字体( cross-origin fonts),一些需要同源字体(same-origin fonts)。 g.
和
载入的任何资源。站点可以使用X-Frame-Options消息头来阻止这种形式的跨域交互。
六、参考
1. 百度百科:同源策略 2. Javascript 的同源策略 3. 浏览器的同源策略 4. 跨域资源共享的10种方式 5. 同源策略和跨域访问