浏览器的同源策略

模板网 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. solr 的Admin界面

    query 1.q(query):定义查询的原始输入字符串。多个条件用AND、OR连接。一定存在在字段前加+号,不存在时在字段前面加-号 ``` company_name:上海有限责任公司 AND

  2. 如何应对缓存穿透和缓存雪崩问题

    分析:这两个问题,说句实在话,一般中小型传统软件企业,很难碰到这个问题。如果有大并发的项目,流量有几百万左右。这两个问题一定要深刻考虑。 缓存穿透,即黑客故意去请求缓存中不存在的数据,导致所有的请

  3. rdb快照持久化

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

  4. Python之系统交互

    我们几乎可以在任何操作系统上通过命令行指令与操作系统进行交互,比如Linux平台下的shell。那么我们如何通过Python来完成这些命令行指令的执行呢?另外,我们应该知道的是命令行指令的执行通常有

  5. php手动编译fileinfo扩展

    某些同学在执行php composer.phar install时,出现错误 90%可能是漏装了PHP的fileinfo扩展了,用宝塔的请直接在宝塔里安装 下载并解压PHP源码包(内含fileinfo

随机推荐

  1. solr 的Admin界面

    query 1.q(query):定义查询的原始输入字符串。多个条件用AND、OR连接。一定存在在字段前加+号,不存在时在字段前面加-号 ``` company_name:上海有限责任公司 AND

  2. 如何应对缓存穿透和缓存雪崩问题

    分析:这两个问题,说句实在话,一般中小型传统软件企业,很难碰到这个问题。如果有大并发的项目,流量有几百万左右。这两个问题一定要深刻考虑。 缓存穿透,即黑客故意去请求缓存中不存在的数据,导致所有的请

  3. rdb快照持久化

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

  4. Python之系统交互

    我们几乎可以在任何操作系统上通过命令行指令与操作系统进行交互,比如Linux平台下的shell。那么我们如何通过Python来完成这些命令行指令的执行呢?另外,我们应该知道的是命令行指令的执行通常有

  5. php手动编译fileinfo扩展

    某些同学在执行php composer.phar install时,出现错误 90%可能是漏装了PHP的fileinfo扩展了,用宝塔的请直接在宝塔里安装 下载并解压PHP源码包(内含fileinfo