Http同源限制

75次阅读

共计 3852 个字符,预计需要花费 10 分钟才能阅读完成。

同源
Cookic
Document.cookic
Http 返回

1. 概述
1.1 含义
1.2 目的
1.3 限制范围
2.Cookie 同源
3.iframe 和多窗口通信
3.1 片段识别符 # 穿数据 父子窗口
3.2window.postMessage() 可不同 父子窗口
3.3LocalStorage 同源父子窗口
4.AJAX 服务器和客户端之间
4.1JSONP 在 script 标签加 callback 参数就是数据体 Get
4.2WebSocket
4.3CORS
参考链接

domcument.domain

1. 概述

1.1 含义

A 网页设置的 Cookie,B 网页不能打开,除非这两个网页“同源”。所谓“同源”指的是“三个相同”。

  • 协议相同
  • 域名相同
  • 端口相同

1.2 目的

同源政策的目的,是为了保证用户信息的安全,防止恶意的网站窃取数据。

设想这样一种情况:A 网站是一家银行,用户登录以后,A 网站在用户的机器上设置了一个 Cookie,包含了一些隐私信息(比如存款总额)。用户离开 A 网站以后,又去访问 B 网站,如果没有同源限制,B 网站可以读取 A 网站的 Cookie,那么隐私信息就会泄漏。
更可怕的是,Cookie 往往用来保存用户的登录状态,如果用户没有退出登录,其他网站就可以冒充用户,为所欲为。
因为浏览器同时还规定,提交表单不受同源政策的限制。

1.3 限制范围

1. 无法读取非同源 cookic.localstorage,indexesDB
.2. 无法读取 dom

  1. 无法向非同源地址发送 AJAX 请求(可以发送,但浏览器会拒绝接受响应)。

另外,通过 JavaScript 脚本可以拿到其他窗口的 window 对象。如果是非同源的网页,目前允许一个窗口可以接触其他网页的 window 对象的九个属性和四个方法。

window.closed
window.frames
window.length
window.location
window.opener
window.parent
window.self
window.top
window.window
window.blur()
window.close()
window.focus()
window.postMessage()

上面的九个属性之中,只有 window.location 是可读写的,其他八个全部都是只读。而且,即使是 location 对象,非同源的情况下,也只允许调用 location.replace 方法和写入 location.href 属性

2.Cookie 同源

次级域名不同的,可以改相同 document.domain 来共享 cookic

举例来说,A 网页的网址是 http://w1.example.com/a.html,B 网页的网址是 http://w2.example.com/b.html,那么只要设置相同的 document.domain

注意,A 和 B 两个网页都需要设置 document.domain 属性,才能达到同源的目的。因为设置 document.domain 的同时,会把端口重置为 null,因此如果只设置一个网页的 document.domain,会导致两个网址的端口不同,还是达不到同源的目的

注意,这种方法只适用于 Cookie 和 iframe 窗口,LocalStorage 和 IndexedDB 无法通过这种方法,规避同源政策,而要使用下文介绍 PostMessage API

3.iframe 和多窗口通信

Iframe 用于在页面中嵌入页面,每个 iframe 形成自己的窗口。自己的 windom 对象。

iframe 窗口之中的脚本,可以获得父窗口和子窗口。
但是,只有在同源的情况下,父窗口和子窗口才能通信;如果跨域,就无法拿到对方的 DOM

document
.getElementById(“myIFrame”)
.contentWindow
.document
// Uncaught DOMException: Blocked a frame from accessing a cross-origin frame.
上面命令中,父窗口想获取子窗口的 DOM,因为跨域导致报错。

反之亦然,子窗口获取主窗口的 DOM 也会报错。

window.parent.document.body
// 报错

对于完全不同源的网站,目前有两种方法,可以解决跨域窗口的通信问题。

片段识别符(fragment identifier)
跨文档通信 API(Cross-document messaging)

3.1 片段识别符 # 传数据

Url# 后面的

如果只是改变片段标识符,页面不会重新刷新。

父窗口可以把信息,写入子窗口的片段标识符。

var src = originURL + ‘#’ + data;
document.getElementById(‘myIFrame’).src = src;

window.onhashchange = checkMessage;

function checkMessage() {
var message = window.location.hash;
// …
}
同样的,子窗口也可以改变父窗口的片段标识符。

parent.location.href = target + ‘#’ + hash;

3.2window.postMessage()可不同

举例来说,父窗口 aaa.com 向子窗口 bbb.com 发消息,调用 postMessage 方法就可以了

// 父窗口打开一个子窗口
var popup = window.open(‘http://bbb.com’, ‘title’);
// 父窗口向子窗口发消息
popup.postMessage(‘Hello World!’, ‘http://bbb.com’);
postMessage 方法的第一个参数是具体的信息内容,第二个参数是接收消息的窗口的源(origin),即“协议 + 域名 + 端口”。也可以设为 *,表示不限制域名,向所有窗口发送。

子窗口向父窗口发送消息的写法类似。

// 子窗口向父窗口发消息
window.opener.postMessage(‘Nice to see you’, ‘http://aaa.com’);

父窗口和子窗口都可以通过 message 事件,监听对方的消息。

// 父窗口和子窗口都可以用下面的代码,
// 监听 message 消息
window.addEventListener(‘message’, function (e) {
console.log(e.data);
},false);
message 事件的参数是事件对象 event,提供以下三个属性。

event.source:发送消息的窗口
event.origin: 消息发向的网址
event.data: 消息内容

下面的例子是,子窗口通过 event.source 属性引用父窗口,然后发送消息。

window.addEventListener(‘message’, receiveMessage);
function receiveMessage(event) {
event.source.postMessage(‘Nice to see you!’, ‘*’);
}

3.3LocalStorage 同源

4.AJAX

除了架设服务器代理(浏览器请求同源服务器,再由后者请求外部服务),有三种方法规避这个限制。

4.1.JSONP

第一步,网页添加一个 <script> 元素,向服务器请求一个脚本,这不受同源政策限制,可以跨域请求。

<script src=”http://api.foo.com?callback=b…;></script>
注意,请求的脚本网址有一个 callback 参数(?callback=bar),用来告诉服务器,客户端的回调函数名称(bar)。

第二步,服务器收到请求后,拼接一个字符串,将 JSON 数据放在函数名里面,作为字符串返回(bar({…}))。

第三步,客户端会将服务器返回的字符串,作为代码解析,因为浏览器认为,这是 <script> 标签请求的脚本内容。这时,客户端只要定义了 bar()函数,就能在该函数体内,拿到服务器返回的 JSON 数据。

4.2.WebSocket

通信协议
使用 ws://(非加密)和 wss://(加密)作为协议前缀。该协议不实行同源政策,只要服务器支持,就可以通过它进行跨源通信

下面是一个例子,浏览器发出的 WebSocket 请求的头信息(摘自维基百科)。

GET /chat HTTP/1.1
Host: server.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==
Sec-WebSocket-Protocol: chat, superchat
Sec-WebSocket-Version: 13
Origin: http://example.com
上面代码中,有一个字段是 Origin,表示该请求的请求源(origin),即发自哪个域名

正是因为有了 Origin 这个字段,所以 WebSocket 才没有实行同源政策。因为服务器可以根据这个字段,判断是否许可本次通信。如果该域名在白名单内,服务器就会做出如下回应。

HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk=
Sec-WebSocket-Protocol: chat

4.3.CORS

相比 JSONP 只能发 GET 请求,CORS 允许任何类型的请求

正文完
 0