跨域
同源策略:浏览器故意设计的一个功能限制
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