浏览器的同源策略

模板网 2021-04-14

一、同源的三个条件

1、域名(二级域名与一级域名之间也算是不同源)
2、端口
3、协议

二、同源策略的意义

浏览器基于用户的隐私安全目的,
防止恶意网站窃取数据(只是浏览器有这个同源策略设置,但是用命令行curl请求某个跨域地址时能得到相应结果),
不允许不同域名的网站之间互相调用ajax XHR对象,
只是不允许XHR对象,对其他的图片、js脚本、css脚本还是可以通过标签跨域调用。
所以css/js/img可以跨域请求(即引用),AJAX不能请求跨域的资源。

同源策略会限制以下三种行为:
1、cookie、localStorage和indexDB无法读取
2、DOM无法获得
3、AJAX 请求无效(可以发送,但浏览器会拒绝接受响应)。

三、跨域访问的四种方式

1、JSONP实现跨域

JSONP(json with padding)方式, 通过script标签请求资源,允许用户在scr地址中传递一个callback参数(callback=abc)即将预先定义好的回调函数名以查询字符串的形式传递给服务端,服务端收到请求后会将要返回的数据用这个callback参数(abc)包裹住再返回,即将请求传入的参数abc作为函数名来包裹住要返回的JSON数据,比如abc(JSON),这样客户端在收到服务端返回的abc(JSON)文件后默认用JS解析执行。通过JSONP就可以随意定制自己的函数来自动处理返回数据了。

jsonp的原理

虽然浏览器默认禁止了跨域访问,但并不禁止在页面中script标签引用其他域下的JS文件,比如线上jquery库,
并可以自由执行引入的JS文件中的function(包括操作cookie、Dom等等)。
根据这一点,可以方便地通过动态创建script节点的方法来实现完全跨域的通信。

jsonp的缺点

1、安全问题,src引用是开放的,所以jsonp的资源都被所有人访问到。
解决方法是用jsonp中的token参数,通过A域和B域共用同一套cookie来验证A的身份。
2、只能用GET方式不能用POST方式获取数据
因为是基于scr引用的,引用是get请求。
3、可被注入恶意代码如?callback=alert(1);
这问题只能用正则过滤字符串的方法解决,过滤callback后的内容不能有括号之类的条件

jsonp代码实现

1.定义数据处理函数
appendHtml(){
    xxxxx
}

2、创建script标签,src的地址执行后端接口,最后加个参数callback=appendHtml.如:
var script=document.createElement('script')
script.src="http://127.0.0.1/getNews?callback=appendHtml"

3、服务端在收到请求后,解析参数,计算返还数据,输出 appendHtml(data) 字符串。
4.前台页面收到服务端返回的appendHtml(data)字符串所构建的script标签,页面加载这个script标签时做为js执行。
此时会调用appendHtml()函数,将data做为参数。

注意:JSONP实现的前提是后端必须有JSONP的API接口,即后端有将前端传入的参数作为函数名包裹数据返回js文件的逻辑。

2、CORS 跨域资源共享 Cross-Origin Resource Sharing

CORS允许浏览器向跨域服务器发出XMLHttpRequest请求,突破了AJAX只能同源使用的限制。CORS需要浏览器和服务器同时支持,目前,所有浏览器都支持该功能,IE浏览器不能低于IE10。CORS原理:浏览器一旦发现AJAX请求跨源,就会自动添加一些附加的头信息,有时还会多出一次附加的请求,但用户不会有感觉。只要服务器实现了CORS接口,就可以跨源通信。

header("Accept-Control-Allow-Origin","*")//允许所有源发起的请求


如果Origin指定的源,不在服务端许可范围内,服务器会返回一个正常的HTTP回应。
但这个响应头信息没有包含Access-Control-Allow-Origin字段。
浏览器接收后就知道出错了,从而抛出一个错误,被XMLHttpRequestonerror回调函数捕获。
这种错误无法通过状态码识别,因为HTTP回应的状态码有可能是200。

如果Origin指定的域名在许可范围内,服务器返回的响应,响应头会包含以下信息字段
Access-Control-Allow-Origin: http://api.bob.com
//允许来自源http://api.bob.com的访问,如果是*则代表允许来自所有源的访问

3、HTML5跨文档通信API window.postMessage

HTML5中最酷的新功能之一就是 跨文档消息传输Cross Document Messaging。 下一代浏览器都将支持这个功能。Facebook已经使用了这个功能,用postMessage支持基于web的实时消息传递。

举例,父窗口aaa.com向子窗口bbb.com发消息,调用postMessage方法如下:

var popup = window.open('http://bbb.com', 'title');
popup.postMessage('Hello World!', 'http://bbb.com');
第一个参数是具体的信息内容(支持任意类型),
第二个参数是接收消息目标窗口的源origin(协议 + 域名 + 端口)也可以设为*,表示不限制域名,向所有窗口发送。

子窗口向父窗口发送消息的写法如下:

window.opener.postMessage('Nice to see you', 'http://aaa.com');

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

window.addEventListener('message', function(event) {
  console.log(e.data);
},false);

4、降域 实现iframe窗口跨域访问 实现不同子域页面cookies共享

当两个网页一级域名相同,只是二级域名不同,浏览器允许通过设置document.domain来实现iframe窗口相互访问或设置cookie。降域方式只适用于同一站点下不同子域名共享cookie或者iframe页面中嵌套的子域名页面之间的访问。降域不适用访问LocalStorage 和 IndexedDB,postMessage()方法可访问LocalStorage。

举例来说,A网页是http://w1.example.com/a.html,B网页是http://w2.example.com/b.html,子域名不同默认情况下会被同源策略阻止访问。只要将两个页面都设置相同的document.domain,两个网页就可以共享Cookie或在iframe窗口下相互访问。

document.domain = 'example.com';

服务器也可以在设置 Cookie 的时候,指定 Cookie 的所属域名为一级域名以后二级域名和三级域名不用做任何设置,都可以读取这个Cookie。比如.example.com。

Set-Cookie: key=value; domain=.example.com; path=/

https://segmentfault.com/a/1190000015764619

相关文章

  1. redis 主从复制

    一、集群的作用 1.主从备份 防止主机宕机 2.读写分离 分担master的任务 3.任务分离,如从服务器分别担任备份工作与计算工作 二、redis集群配置 Master配置 1、关闭rdb快照

  2. aof恢复与rdb服务器迁移

    一、不小心flushall或flushdb了怎么办??? 只有aof还不够。 因为如果发生重写,aof文件里就什么都没有了。 所以要及时shutdown nosave,防止aof重写!!! 然后将a

  3. python多线程

    一、介绍 多任务可以由多进程完成,也可以由一个进程内的多线程完成。 我们前面提到了进程是由若干线程组成的,一个进程至少有一个线程。 由于线程是操作系统直接支持的执行单元,因此,高级语言通常都内置多线

  4. rdb快照持久化

    一、持久化的方式 什么是持久化:redis所有数据保存在内存中,对数据的更新将异步保存到磁盘上。 持久化:即把数据存储于断电后不会丢失的设备中,通常是硬盘。 常见的持久化方式:主从:通过从服务器保存

  5. php配置加载器

    配置加载器 当我们使用App::cfg系列方法获取配置时,wulaphp是通过配置加载器先加载配置然后再返回配置项对应值的(当然可以返回整个配置数组)。配置加载器ConfigurationLoade

随机推荐

  1. redis 主从复制

    一、集群的作用 1.主从备份 防止主机宕机 2.读写分离 分担master的任务 3.任务分离,如从服务器分别担任备份工作与计算工作 二、redis集群配置 Master配置 1、关闭rdb快照

  2. aof恢复与rdb服务器迁移

    一、不小心flushall或flushdb了怎么办??? 只有aof还不够。 因为如果发生重写,aof文件里就什么都没有了。 所以要及时shutdown nosave,防止aof重写!!! 然后将a

  3. python多线程

    一、介绍 多任务可以由多进程完成,也可以由一个进程内的多线程完成。 我们前面提到了进程是由若干线程组成的,一个进程至少有一个线程。 由于线程是操作系统直接支持的执行单元,因此,高级语言通常都内置多线

  4. rdb快照持久化

    一、持久化的方式 什么是持久化:redis所有数据保存在内存中,对数据的更新将异步保存到磁盘上。 持久化:即把数据存储于断电后不会丢失的设备中,通常是硬盘。 常见的持久化方式:主从:通过从服务器保存

  5. php配置加载器

    配置加载器 当我们使用App::cfg系列方法获取配置时,wulaphp是通过配置加载器先加载配置然后再返回配置项对应值的(当然可以返回整个配置数组)。配置加载器ConfigurationLoade