跨域
跨域
同源策略
浏览器故意设计的一个功能限制
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 的数据,即不允许跨域
举例
假设 lucas.com/index.html 引用了 cdn.com/1.js
那么就是说 1.js 运行在源 lucas.com 里
这跟cdn.com 没有关系,虽然 1.js 从那下载
所以 1.js 就只能获取 lucas.com 的数据
不能获取 1.lucas.com 或者 qq.com 的数据
运行在哪个域名里,就只能访问这个域名的数据
这是浏览器的功能
为了保护用户隐私
如果没有同源策略
以 QQ 空间为例
源为 https://user.qzone.qq.com
假设,当前用户已经登录(用 Cookie)
假设,AJAX 请求 /friends.json 可获取用户好友列表
到目前为止都很正常
黑客来了
假设好基友(黑客伪装)分享了一个链接给你(https://qzone-qq.com)(钓鱼网站)
当你点开这个网页时,这个网页也请求你的好友列表
https://user.qzone.qq.com/friends.json
黑客成功获取好友列表
问题的根源
无法区分发送者
QQ空间页面里的 JS 和黑客网页里的 JS
法的请求几乎没有区别(referer 有区别)
如果后台开发者没有检查 referer,那么就完全没区别
所以如果没有同源策略,任何页面都能偷 QQ空间的数据
甚至支付宝的余额
安全原则:安全链条的强度取决于最弱的一环
万一这个网站的后端开发工程师忘了检查referer
所以浏览器应该主动预防这种偷数据的行为
总之,浏览器为了用户隐私,设置了严格的同源策略
事件模拟
步骤
创建目录
qq-com 里面有一个 server.js,用来模拟 QQ空间
lucas.com 里面也有一个 server.js,用来模拟黑客网站
qq-com
/index.html 是首页
/qq.js 是 JS 脚本文件
/friends.json 是模拟的好友数据
端口监听为 8800,访问 http://127.0.0.1:8800
lucas-com
/index.html 是首页
/lucas.js 是 JS 脚本文件
端口监听为9900,访问 http://127.0.0.1:8800
完成以上步骤就可以测出端口号不同无法互相访问
hosts
设置本地域名映射
让 qq.com 映射到 127.0.0.1
就可以访问 http://qq.com:8800/index.html
让 lucas.com 映射到 127.0.0.1
就可以访问 http://lucas.com:9900/index.html
如何设置hosts
修改时需要用管理员权限操作
跨域 AJAX
正常使用 AJAX
在 qq.com:8800 里运行的 JS 可以访问 /friends.json
黑客偷数据
请求发送成了,因为 qq.com 后台有 log,访问状态也是200
但黑客拿不到响应,浏览器不给数据给黑客
在 lucas.com:9900 里运行的 JS 不能访问 qq.com:8800/里的数据
浏览器需要 CORS 才能访问
!可以跨域使用 CSS、JS 和图片等
同源策略限制的是数据的访问,引用 CSS、JS 和图片的时候,其实并不知道其内容,只是在引用
如何跨域
方法一:CORS
问题根源
浏览器默认不同源之间不能互相访问数据
但是 自己的网站之间有时候是需要互相访问的,但还是被浏览器阻止了
用CORS(跨域资源共享)
如果需要共享网站数据,需要提前声明
在共享网站的响应头里写上前来拿数据的网站就行
1 |
|
方法二:JSONP
定义
JSONP 和 JSONP 没什么关系
当没有CORS时,怎么跨域 (兼容 IE)
虽然不能访问 .json
但是可以引用 .js
只要让 JS 包含数据就可以了
优点:
- 它不像 Ajax 请求那样受到同源策略的限制, JSONP 可以跨越同源策略;
- 兼容 IE 可以在更加古老的浏览器运行
缺点:
- 没有 AJAX 精确,没有状态码,也不知道响应头是什么,只知道成功失败
- 由于是 script 标签,所以只能发 get 请求 ,不支持 post 请求
步骤
lucas.com 访问 qq.com
qq.com 将数据写到 /friends.js
lucas.com 用 script 标签引用 /friends.js
/friends.js 执行事先定义好的 window.xxx 函数
/friends.js 执行window.xxx({friends:[…]})
然后 lucas.com 就通过 window.xxx 获取到数据了
window.xxx 就是一个回调
1 |
|
1 |
|