跨域、CORS、JSONP

Rinsann 2021年09月01日 550次浏览

跨域、CORS、JSONP

跨域关键知识

同源策略

  • 浏览器故意设计的一个功能限制

CORS

  • 突破浏览器限制的一个方法

JSONP

  • IE时代的妥协

同源策略

同源定义

  • window.origin 或 location.origin 可以得到当前源
  • 源 = 协议 + 域名 + 端口号

如果有两个url的

  • 协议、域名、端口号,完全一致,那么这两个url就是同源的

举例

同源策略定义

浏览器规定

  • 如果JS运行在源A里,那么就只能获取源A的数据
  • 不能获取源B的数据,即不允许跨域

举例(省略http协议)

  • 假设rick.com/index.html 引用了 cdn.com/1.js
  • 那么就说 1.js运行在源rick.com里
  • 注意这跟cdn.com没有关系,虽然1.js从它那下载
  • 所以1.js就只能获取rick.com的数据
  • 不能获取1.rick.com 或者 qq.com 的数据

这是浏览器的功能

  • 浏览器就是这样设计的。

浏览器这样做的目的是为什么?为了保护用户隐私!

如果没有同源策略

以QQ空间为例

  • 源为 https://user.qzone.qq.com
  • 假设,当前用户已经登录(用cookie)
  • 假设,AJAX请求 /rick.json 可获取用户好友列表
  • 到目前为止都很正常

黑客来了

问题的根源

无法区分发送者

  • QQ空间页面里的JS和黑客网页里的JS发的请求几乎没有区别(Referrer Policy有区别)
  • 如果后台开发者没有检查Referrer,那么就完全没有区别
  • 所以,没有同源策略,任何页面都能偷QQ空间的数据,甚至支付宝余额!

那检查Referrer不就好了

  • 安全原则:安全链条的强度取决于最弱的一环
  • 万一这个网站的后端开发工程师不知道呢
  • 所以浏览器应该主动预防这种偷数据的行为,总之浏览器为了保护用户隐私,设置了严格的同源策略

同源策略:不同源的页面之间,不准互相访问数据

演示

创建目录

  • qq-com 里面有一个server.js,用来模拟QQ空间
  • rick-com里面有一个server.js,用来模拟黑客网站‘

qq-com

  • /index.html 是首页
  • /qq.js 是JS脚本文件
  • /friends.json 是模拟的好友数据
  • 端口监听为8888,访问http://127.0.0.1:8888

rick-com

hosts

设置本地域名映射

如何设置hosts

  • 需要使用管理员权限操作
  • 使用管理员权限记事本打开 C:\Windows\System32\drivers\etc\hosts 文件
  • 在最后面添加 127.0.0.1 rick.com 和 127.0.0.1 qq.com

跨域AJAX

正常使用AJAX

  • 在qq.com:8888 里运行的JS可以访问/friends.json

黑客偷数据

  • 在rick.com:9999 里面运行的JS不能访问
  • 浏览器需要CORS

提问

  • 黑客的请求发送成功没有?答:成功了,因为qq.com后台有log

  • 黑客拿到响应没有?答:没有,因为浏览器不给数据给它

  • 为什么a.qq.com访问qq.com也算跨域?

  • 答:因为历史上出现过不同公司共用域名,a.qq.com 和 qq.com 不一定是同一个网站,浏览器谨慎起见,认为这是不同的源

  • 为什么不同端口也算跨域?

  • 答:原因同上,一个端口一个公司。记住安全链条的强度取决于最弱的一环,任何安全相关的问题都要谨慎对待

  • 为什么两个网站的ip是一样的,也算跨域?

  • 答:原因同上,ip可以共用

  • 为什么可以跨域使用CSS、JS和图片等?

  • 答:同源策略限制的是数据访问,我们引用CSS、JS和图片的时候,其实并不知道内容,只是在引用。

现实会问:请问怎么跨域

解法1:CORS

问题根源

  • 浏览器默认不同源之间不能互相访问数据
  • 但是qq.com和rick.com其实都是同一家的网站
  • 现在我就是想要两个网站互相访问,浏览器为什么阻止

所有就要用CORS

  • 浏览器说,如果要共享数据,需要提前说明
  • 怎么声明?浏览器说:qq.com在响应头里写rick.com可以访问
  • 具体语法:response.setHeader('Access-Control-Allow-Origin', 'http://rick.com:9999')

JSONP

定义

  • JSONP和JSON没有关系
  • 没有CORS怎么跨域
  • 我们可以随意引用JS,虽然我们不能访问qq.com:888/friends.json,但是我们可以引用它
  • 只要让JS包含数据就可以了

步骤

  • rick.com访问qq.com
  • rick.com 用script标签引用/friends.js
  • /friends.js执行事先定义好的window.xxx函数
  • /friends.js 执行 window.xxx({friends:[...]})
  • 如何rick.com就通过window.xxx获取到数据了,window.xxx就是一个回调。

优化

xxx能不写死吗?

  • window.xxx能不能改成其他名字
  • 其实名字不重要,只要frank.com定义的函数名和qq.com/friends.js执行的函数名是同一个即可
  • 那就把名字传给/friends.js!

再次优化

封装

  • 初级程序员学API,中级程序员学封装
  • 封装成jsonp(‘url’).then(f1,f2)

JSONP是什么(优缺点)

jsonp就是我们在跨域的时候由于当前不支持CORS,必须使用另外一种方式来跨域

于是我们就请求一个js文件,这个js文件会执行一个回调,回调里面就有我们需要的数据

回调的名字是跨域随机生成,我们把这个名字以callback参数传给后台,后台会把这个函数返回给我们并执行

  • 优点:支持IE、可以跨域
  • 缺点:它是script标签所以拿不到状态码拿不到header,只支持get请求不支持post