前后端分离 跨域 CORS JSONP

242 阅读3分钟

跨域

同源策略:浏览器故意设计的一个功能限制

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

JSONP:   兼容IE的跨域方法

同源策略

源的定义

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

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

举例
https://qq.com     https://www.baidu.com 不同源
https://baidu.com  https://www.baidu.com 不同源

同源策略定义

浏览器规定:如果JS运行在源A里,那么就只能获取源A的数据;不能获取源B的数据,即不允许跨域

举例(省略http协议)
假设 frank.com/index.html 引用了 cdn.com/1.js
那么就说[1.js 运行在源 frank.com里]
注意这跟 cdn.com 没有关系,虽然 1.js是从它那下载的
所以 1.js只能获取 frank.com 的数据
不能获取 1.frank.com 或者 qq.com 的数据

这是浏览器的功能,故意这么设置的,为了保护用户隐私

如果没有同源策略

以QQ空间为例
源为  https://user.qzone.com
假设  当前用户已经登录
假设  AJAX请求 /friends.json 可获取用户的好友列表

黑客来了
分享 https://qzone-qq.com 给你(钓鱼网址)
点开这个网页,这个网页也请求你的好友列表
https://user.qzone.qq.com/friends.json
那么就会偷走你的好友列表

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

那检查referer不就好了
安全原则,安全链条的强度取决于最弱的一环
有可能这个网站的后端工程师 忘记设置检查referer
所以浏览器应该主动预防这种偷数据的行为
总之,浏览器为了用户隐私,设置了严格的同源策略

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

实际同源演示

创建两个网站

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

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

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

hosts 设置本地域名映射
让qq.com    映射到127.0.0.1,就可以访问 http://qq.com:8888/index.html
让frank.com 映射到127.0.0.1,就可以访问 http://frank.com:9999/index.html

跨域AJAX

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

黑客偷数据
在frank.com:9999里运行的JS不能访问
黑客的请求发成功了,但是没有拿到响应,浏览器不给他数据
浏览器需要CORS

怎么跨域

CORS
问题根源
浏览器默认不同源之间不能互相访问数据
但是qq.com 和 frank.com 都是我的网址
就想让这2个网站互相访问,浏览区为什么阻止

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

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

IE不支持CORS,使用JSONP

定义
JSONP和JSON没有任何关系

需求
没有CORS,怎么跨域
因为我们可以随便引用JS
虽然我们不能访问qq.com:8888/friends.json
但是我们能引用qq.com:8888/friend.js
JS不是数据,我们可以让JS包含数据

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

优化代码
window.xxx写死了,容易重名,改成其它名字
其实名字不重要,只要frank.com 定义的函数名和qq.com/friends.js执行的函数名是同一个即可
把名字传给/friends.js
使用随机数当名字

代码链接: github.com/shuaigechen…

详细资料点击 CORS