同源与跨域

谈谈同源策略

什么是同源

首先,得说一下什么是源,这个词的英文叫做origin,也就是源头,起源的意思,对于浏览器而言,一个网页的源包含了它的协议(protocol)、端口(port)和主机名(host)这三个内容,缺一不可,同源,就是这前面所列举的三个要素全部相同即为同源。

对与http协议,它具有默认端口为80端口,也就是说,在不写端口的时候浏览器会为你默认补上:80作为端口号,相当于,一个没有写端口号和一个写了:80端口的网址,只要它们的协议和主机名相同,它们也是同源的,像这样:
http://www.xxx.comhttp://www.xxx.com:80实质上也是同源的。

而对于https协议,它的默认端口为443,和上面所说的http协议一样,它在不写端口号时也与写了443的同协议主机名的url同源。

为什么要同源策略

同源策略是由Netscape提出的一个著名的安全策略,现在能支持JavaScript的浏览器都支持同源策略,所谓的同源策略就是一个源下面的在其他源下加载资源的一种限制。
实际上同源策略并不是一个强制的要求,而只是一种规范,现在各大浏览器中的同源策略则是对这种规范的一种实现,它作为浏览器中的一种最核心的安全功能,现在是不可或缺的,如果没有了同源策略,任一个站点都可以通过跨域的方式来访问你的所有数据资源,甚至读取你浏览器所有的保存的cookie资源,这样就毫无安全性可言了。
浏览器同源政策及规避方法

跨域的实现方式

什么是跨域

前面所讲的,同源策略就是对不同origin资源的读写的一种限制,而跨域就是这种限制,将从另一个origin中去获取资源,并进行读写。

跨域的方式

  1. 降域
    通过将要去跨域访问的域与要被访问资源的域的document.domain设置成相同值,来将域名降域,这样浏览器就会认为它们具有相同的源,以此来实现跨域。
    降域的注意点:

    • 只能往上级域名去设置域名,也就是说,当两者的域名分别为http://a.xx.com:80http://xx.com:80,这时要设置跨域的域名,这能设置成http://xx.com:80,而不能设置为前者,所欲它只适用于父级域名完全相同的情况。
    • 由于是降域实现的跨域,所以只要其中一个域被攻击,其它域也会被影响,也就是说,安全性能并不好。
    • 他只对document.domain以上的资源生效,在设置document.domain一下的内容中,他没有效果。
    • 它只对iframe生效,所以就没什么用了
  2. JSONP
    JSONP的全名叫做json with padding,它和JSON没有关系。
    由于同源策略的限制,如上所言 http://www.example.comhttp://www.example2.com来个url的服务器的数据不能互相获取和读写,而script标签则是一个例外,我们可以再script标签中去应用外部的插件资源等内容,而JSONP也是利用这一特性来跨过同源策略的限制,来实现跨域获取数据的需求。

JSONP可以通过动态添加script,并且在src属性中设置想要的资源和callback,从而去获取数据,像这样

1
2
3
4
5
<script>
var script = document.createElement("script");
script.src = "//example.com/data?callback=getInfo";
document.body.appendChild(script);
<script>

也可以直接使用静态的标签

1
2
<script src="//example.com/data?callback=getInfo">
</script>

本质上,这两种方式并没有区别
JSONP所存在的问题

  • 使用远程网站的script标签时,若远程网站的script标签本身存在着漏洞,则引入的网站也会被影响,跨域的网站需要相互验证,并设置token。来保证安全性。
  • 基于script标签的资源能能get数据,不能post数据,也就是说,只能读,不具有写的功能。
  • callback可能被注入一些恶意字符,可采用正则过滤的方式来消除这种错误。

一般而言,JSONP的安全性问题和恶意字符的问题都能够得到解决。

  1. CORS
    它的全称叫做Cross-Origin Resource Sharing,也就是跨域资源共享的意思,它是一种W3C规范,允许从浏览器的跨域通信。通过建立XMLHttpRequest对象的header,CORS允许开发者使用相同的习惯作为跨域请求工作。
    Chrome、Firefox、Opera和Safari都是用XMLHttpRequest2中的对象,而IE则使用类似的XDomainRequest。

具体使用方法:
在要被请求的文件中声明header(“Access-Control-Allow-Origin: example.org”)即可

在IE10及以下,CORS都具有兼容性问题。