同源政策与跨域问题

cyber-security

同源政策与跨域问题

什么是浏览器的同源政策?

维基百科对同源政策的定义。简单来说,为了保护用户的数据安全,浏览器规定,对于不同源的网页,它们之间以下的资源交互行为是被禁止的:

  1. 持久化数据无法获取,包括 Cookie, LocakStorage, IndexDB
  2. DOM 无法获取
  3. AJAX 请求不能发送

仔细想想,以上 3 种行为对于用户安全来说,都是非常危险的。持久化数据通常含有用户的身份信息、登录态信息;至于 DOMAJAX 这两者的权限都可能导致网页被植入恶意代码。

同源的严格定义

如果说两个网页同源,是指以下 3 个部分都相同:

  • 协议
  • 主机
  • 端口

举例来说,http://www.example.com/dir/page.html 这个网址,协议是 http://,域名是 www.example.com,端口是 80(默认端口可以省略)。它的同源情况如下。

不受同源政策限制的资源交互行为

需要明确的一点是,同源政策对于 HTML 标签是没有限制的,这使得网页可以从远程服务器获取资源文件,主要有以下标签:

  • script 标签用来获取远程脚本文件,JSONP 跨域方式就是利用了这一点
  • link 标签用来获取远程 CSS 文件
  • image 标签用来获取远程图片文件
  • audio 标签用来获取远程音频文件
  • video 标签用来获取远程视频文件

如何规避同源政策来实现数据获取?

在实际开发中,需要突破同源政策的限制来获取数据,主要是在使用 AJAX 向非同源服务器发送请求的场合。主要使用下面的几种方式来规避同源政策获取数据:

  1. 跨域资源共享
  2. JSONP
  3. 服务器代理转发
  4. 跨文档通信 Cross-document messaging。这是 HTML5 为了解决跨文档通信引入的新 API:window.postMessage,但是这种方式能获取的内容是作了严格限制的,原因仍然是出于安全考虑。
  5. WebSocket

跨域资源共享

即 Cross-Origin Resource Sharing。这是一个很大的话题,而且基本由后端实现 CORS 的支持,详情见参考链接 3 和 4,两篇文章讲的非常清晰。

JSONP

JSONP 是服务器与客户端跨源通信的常用方法。最大特点就是简单适用,老式浏览器全部支持,服务器改造非常小。

它的基本思想是,网页通过添加一个<script>元素,向服务器请求 JSON 数据,这种做法不受同源政策限制;服务器收到请求后,将数据放在一个指定名字的回调函数里传回来。

首先,网页动态插入<script>元素,由它向跨源网址发出请求。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
function addScriptTag(src) {
var script = document.createElement('script')
script.setAttribute('type', 'text/javascript')
script.src = src
document.body.appendChild(script)
}

window.onload = function() {
addScriptTag('http://example.com/ip?callback=foo')
}

function foo(data) {
console.log('Your public IP address is: ' + data.ip)
}

上面代码通过动态添加<script>元素,向服务器example.com发出请求。注意,该请求的查询字符串有一个callback参数,用来指定回调函数的名字,这对于 JSONP 是必需的。

服务器收到这个请求以后,会将数据放在回调函数的参数位置返回。

1
2
3
foo({
ip: '8.8.8.8'
})

由于<script>元素请求的脚本,直接作为代码运行。这时,只要浏览器定义了foo函数,该函数就会立即调用。作为参数的 JSON 数据被视为 JavaScript 对象,而不是字符串,因此避免了使用JSON.parse的步骤。
此外, JSONP 的方式仅限于 GET 方法的网络请求。

架设代理服务器,转发请求

架设一个同源的服务器,浏览器向该同源服务器发送 AJAX 请求,再由该服务器转发请求到外部非同源服务器。

跨文档通信

WebSocket

参考链接

  1. 同源政策及其规避方法

  2. Same-origin policy

  3. 跨域资源共享 CORS 详解 - 阮一峰

  4. CORS - MDN