天天看点

Web安全之同源策略与跨域访问一、怎样才算是同源二、IE特例三、读写权限四、同源策略示例五、跨域访问资源六、参考

古语云:“无规矩不成方圆”。同源策略(

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

中会报下面的异常:

Web安全之同源策略与跨域访问一、怎样才算是同源二、IE特例三、读写权限四、同源策略示例五、跨域访问资源六、参考

IE

中会报下面的异常:

Web安全之同源策略与跨域访问一、怎样才算是同源二、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

上的数据进行读写操作。

请求及响应过程如下:

Web安全之同源策略与跨域访问一、怎样才算是同源二、IE特例三、读写权限四、同源策略示例五、跨域访问资源六、参考

通过在

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: 
           

多个域名之间用逗号分隔,表示对所示域名提供跨域访问权限。”*”表示允许所有域名的跨域访问。

客户端可以有两种行为:

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

):
<script src="http://localhost:8081/test_data.js" type="text/javascript"></script> 
<script>
   function test_handler(data) { 
        console.log(data);  
   }  
</script> 
           
服务器端的

Javascript

脚(

http://localhost:8081/test_data.js

):
test_handler('{"data": "something"}');
           
为了动态实现

JSONP

请求,可以使用

Javascript

动态插入

<script>

标签:
<script type="text/javascript">
   // this shows dynamic script insertion
   var script = document.createElement('script');
   script.setAttribute('src', url);
   // load the script
   document.getElementsByTagName('head')[].appendChild(script); 
</script>
           

JSONP

协议封装了上述步骤,

jQuery

中统一实现在

Ajax

中(其中

data type

JSONP

):

http://localhost:8080/test?callback=test_handler

为了支持

JSONP

协议,服务器端必须提供特别的支持,另外

JSONP

只支持

GET

请求。

利用

jQuery

中的

Ajax

实现

jsonp

跨域请求可以查看我之前的博客

JavaScript实现百度搜索suggestion功能

3. document.domain(双向跨域)

通过修改

document

domain

属性,我们可以在域和子域或者不同的子域之间通信。同域策略认为域和子域隶属于不同的域,比如

www.a.com

sub.a.com

是不同的域,这时,我们无法在

www.a.com

下的页面中调用

sub.a.com

中定义的

JavaScrip

t方法。但是当我们把它们

document

domain

属性都修改为

a.com

,浏览器就会认为它们处于同一个域下,那么我们就可以互相调用对方的

method

来通信了。

注意:浏览器单独保存端口号。任何的赋值操作,包括

document.domain

=

document.domain

都会以

null

值覆盖掉原来的端口号。因此

company.com:8080

页面的脚本不能仅通过设置

document.domain

=

"company.com"

就能与

company.com

通信。赋值时必须带上端口号,以确保端口号不会为

null

。另外,使用

document.domain

来安全是让子域访问其父域,需要同时将子域和父域的

document.domain

设置为相同的值。必须要这么做,即使是简单的将父域设置为其原来的值。没有这么做的话可能导致授权错误。

4. window.postMessage(双向跨域)

window.postMessage

HTML5

定义的一个很新的方法,这个方法可以很方便地跨

window

通信。由于它是一个很新的方法,所以在很旧和比较旧的浏览器中都无法使用。

例如:
targetWindow.postMessage(data, origin);
           
1

.data

:要传递的数据,

html5

规范中提到该参数可以是

JavaScript

的任意基本类型或可复制的对象,然而并不是所有浏览器都做到了这点儿,部分浏览器只能处理字符串参数,所以我们在传递参数的时候需要使用

JSON.stringify()

方法对对象参数序列化,在低版本IE中引用

json2.js

可以实现类似效果。

2.

origin

:字符串参数,指明目标窗口的源,协议+主机+端口号[+URL],

URL

会被忽略,所以可以不写,这个参数是为了安全考虑,

postMessage()

方法只会将

message

传递给指定窗口,当然如果愿意也可以建参数设置为”*”,这样可以传递给任意窗口,如果要指定和当前窗口同源的话设置为”/”。

接收消息:

window.addEventListener('message', handler, false);
           

handler

event.data

postMessage

发送来的数据,

event.origin

是发送窗口的

origin

event.source

是发送消息的窗口引用

5. 跨域内嵌的资源

a.

<script src="..."></script>

标签嵌入跨域脚本。语法错误信息只能在同源脚本中捕捉到

b.

<link rel="stylesheet" href="..." target="_blank" rel="external nofollow" >

标签嵌入

CSS

c.

<img>

嵌入图片。支持的图片格式包括

PNG

,

JPEG

,

GIF

,

BMP

,

SVG

,…

d.

<video>

<audio>

嵌入多媒体资源。

e.

<object>

,

<embed>

<applet>

的插件。

f.

@font-face

引入的字体。一些浏览器允许跨域字体( cross-origin fonts),一些需要同源字体(same-origin fonts)。

g.

<frame>

<iframe>

载入的任何资源。站点可以使用X-Frame-Options消息头来阻止这种形式的跨域交互。

六、参考

1. 百度百科:同源策略

2. JavaScript 的同源策略

3. 浏览器的同源策略

4. 跨域资源共享的10种方式

5. 同源策略和跨域访问