1 min read

JavaScript 同源策略

最近大量用 ajax,自然要面对跨域问题。什么是跨域?先来定义同源。

同源的定义

同源指两个网页,它们的协议(protocal)、端口(port)和主机(host)一致。

比如下面这两个网页:

  1. http://www.example.com/sam.html
  2. https://www.example.com/sam.html

它们的协议不一,一个是 http,一个是 https,所以不同源。同理可推端口、主机。

不同源,即跨域。

同源策略的内容

同源策略是出于安全考虑设计的,那么,它具体指什么?

MDN 上是这样说的

The same-origin policy restricts how a document or script loaded from one origin can interact with a resource from another origin.

“同源策略限制了一个域的文档或脚本如何与另一个域的资源交互”。

啥?我们可以分几种情况说明。

读取资源

我们通常说的跨域,多是针对 XMLHttpRequest – ajax 技术的基础之一。

假设我在本地搭建了一个服务器环境,网址是 http://localhost/,主页 index.html 中有一段 JavaScript 代码如下:

$(function(){
   $.get('sam.html',function(data){
       $('body').html(data)
   })
})

sam.html 文件位于 index.html 同一文件夹下。结果显示,我们成功 GETsam.html 文件的内容。

那么再尝试一下,从本地 GET 远程文件如何。这里代码中加入一个对照组:

$(function(){
   $.get('http://www.zfanw.com/?12132313232',function(data){
       $('body').html(data);
   });
    $.get('sam.html',function(data){
        console.log(data);
    })
});

我们看看 Google Chrome 30.0.1599.114 控制台下的情况:

google chrome 控制台信息

Google Chrome 控制台报错了:

XMLHttpRequest cannot load http://www.zfanw.com/?12132313232. Origin http://127.0.0.1 is not allowed by Access-Control-Allow-Origin.

因为 http://localhosthttp://www.zfanw.com 不同源,所以浏览器会禁止来自 localhost 的脚本访问跨域资源。

这很容易理解,你家里当然不会允许陌生人随便进去,要进,得要你邀请了才行。Chrome 控制台中提到的 Access-Control-Allow-Origin,正是我们邀请其它域的脚本访问的方法,具体用法请看 enable cross-origin resource sharing 网站的说明

写入

跨域写入的情况可以参照读取部分的说明,这也是时下非常常见的,比如我有一个 API 服务器部署在另一个域名下,但我依然可以通过 ajax 请求将数据存储到 API 服务器中,只要我们在 Access-Control-Allow-Origin 中许可了来自其它源的请求。

执行

出于安全考虑,同源策略默认不允许源 A 的脚本读取源 B 的资源,但却允许执行源 B 的资源。

这个概念也有些拗⼝。

简单说,我这个博客,调用了 Google CDN 提供的 jQuery,它的源显然与我的博客不同,但我却可以用它来操作我的博客页面 DOM,它也可以读取我的 cookie、localStorage 等。

假设一个场景,Google CDN 上的 jQuery 被注入了恶意代码,或者被劫持,指向另一个带有恶意代码的 jQuery,则引用它的网站就很危险了,因为这恶意 jQuery 现在可以读取我们网站的内容,并且向其它地方写入。

报告问题 修订

如果你有自建 https 代理的需求,欢迎尝试 Phantom,一键搭建,方便快捷。查看 demo