跨域 Note-FrontEend-30

108 阅读4分钟

跨域的相关知识,内容包括跨域的关键知识、同源策略、演示、CORS、JSONP。

一、跨域的关键知识

1. 同源策略

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

2. CORS

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

3. JSONP

  • IE 时代的妥协

二、同源策略

1. 同源定义

源:window.origin 或 location.origin 可以得到当前源

源 = 协议 + 域名 + 端口号

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

https://qq.com、https://www.baidu.com 不同源
https://baidu.com、https://www.baidu.com 不同源

2. 同源定义策略

浏览器规定

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

举例(省略 http 协议)

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

这是浏览器的功能!

浏览器故意这样设计的,目的是为了保护用户隐私!

3. 如果没有同源策略

以 QQ 空间为例: 源为 https://user.qzone.qq.com,假设当前用户已经登录,假设,AJAX 请求 /friends.json 可获取用户好友列表,到目前为止都很正常

黑客来了: 假设你的女神分享 https://qzone-qq.com 给你,实际上这是一个钓鱼网站,你点开这个网页,这个网页也请求你的好友列表,https://user.qzone.qq.com/frends.json,请问,你的好友列表是不是就被黑客偷偷偷走了,好像是哦

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

那检查 referer 不就好了?

安全原则:安全链条的强度取决于最弱的一环

所以浏览器应该主动预防这种偷数据的行为,总之,浏览器为了用户隐私,设置了严格的同源策略

三、演示

1. 开两个服务器

创建两个目录,qq-com 里面有一个 server.js,用来模拟 QQ 空间,eddie-com 里面有一个 server.js,用来模拟坏人的网站

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

eddie-com:/index.html 是首页,/eddie.js 是 JS 脚本文件,端口监听为 9999,访问 http://127.0.0.1:9999

2. hosts 设置本地域名映射

让 qq.com 映射到 127.0.0.1,就可以访问 http://qq.com:8888/index.html

让 eddie.com 映射到 127.0.0.1,就可以访问 http://eddie.com:9999/index.html

3. 模拟黑客偷数据

正常使用 AJAX: 在 qq.com:8888 里运行的 JS 可以访问 /friends.json

黑客偷数据: 在 eddie.com:9999 里运行的 JS 不能访问!浏览器需要 CORS

  1. 黑客的请求发成功了没有?
    • 答:成功了,因为 qq.com 后台有 log
  2. 黑客拿到响应了没有?
    • 答:没有,因为浏览器不给数据给它
  3. 就没有浏览器不限制跨域吗?
    • 如果不限制,就是浏览器 bug 了,快向浏览器反馈

4. 其他疑问

  1. 为什么 a.qq.com 访问 qq.com 也算跨域?
    • 因为历史上,出现过不同公司共用域名
    • a.qq.com 和 qq.com 不一定是同一个网站
    • 浏览器谨慎起见,认为这是不同的远
  2. 为什么不同端口也算跨域?
    • 原因同上,一个端口一个公司
    • 记住安全链条的强度取决于最弱一环
    • 任何安全相关的问题都要谨慎对待
  3. 为什么两个网站的 IP 是一样的,也算跨域?
    • 原因同上,IP 可以共用
  4. 为什么可以跨域使用 CSS、JS 和图片等?
    • 同源策略限制的是数据访问
    • 我们引用 CSS、JS 和图片的时候,其实不知道其内容,我们只是在引用
    • 不信我问你,你能知道 CSS 的第一个字符是什么吗?

四、CORS

浏览器说,如果要共享数据,需要提前声明!qq.com 在响应头里写 eddie.com 可以访问

具体语法:浏览器说:都在文档里,去看 MDN 文档嘛

Access-Control-Allow-Origin:http://foo.example

IE 说:你猜我支持不支持

五、JSONP

没有 CORS,怎么跨域

记不记得我们可以随意引用 JS,虽然我们不能访问 qq.com:8888/friends.json,但是我们能引用 qq.com:8888/friends.js 啊!这有什么用?JS 又不是数据,我们让 JS 包含数据不就好了......

eddie.com 访问 qq.com

qq.com 将数据写到 /friends.js,eddie.com 用 script 标签引用 /friends.js,/friends.js 执行,执行什么呢?eddie.com 事先定义好 window.xxx 函数,/friends.js 执行 window.xxx({friend:[...]}),然后 eddie.com 就通过 window.xxx 获取到数据了,window.xxx 就是一个回调啊!

这 TM 都能想到,人才啊!这是很多前端工程师一起想出来的

优化 -- xxx 能不写死吗?

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

再优化 -- 封装!

初级程序员学 API,终极程序员学封装。封装成 jsonp('url').then(f1,f2)

「资料来源:©饥人谷」