同源策略
浏览器有同源策略,如果两个URL的协议,域名,端口完全一致才是同源
有一个不一致就是跨域
示例
以当前页面为例:https://sugarat.top/bigWeb/browser/cros.html
- 协议:https
- 域名:sugarat.top
- 端口:443 (https默认443,http默认80)
URL | 是否同源 | 理由 |
sugarat.top | ✅ | 协议,域名,端口 均一致 |
sugarat.top | ❌ | 协议,端口不一致 |
sugarat.top:8080 | ❌ | 端口 不一致 |
ep.sugarat.top | ❌ | 域名 不一致 |
imgbed.sugarat.top | ❌ | 域名 不一致 |
同源策略限制
- DOM: 禁止操作非源页面的DOM与JS对象
- 这里主要场景是iframe跨域的情况,非同源的iframe是限制互相访问的
- XmlHttpRequest: 禁止使用XHR对象向不同源的服务器地址发起HTTP请求,即不能发送跨域ajax请求
- 主要用来防止CSRF(跨站请求伪造)攻击
- 本地存储: Cookie、LocalStorage 和 IndexDB 无法跨域读取
非同源也有可以通信的方案,后文会做出介绍
为什么需要同源策略🤔
这里先列举反例
例1:如果iframe可以跨域,就会有以下攻击场景
- 一个假网站
https://a.com
,内部嵌套一个全屏的iframe标签指向一个银行网站https://b.com
- 用户访问假网站除了域名,别的部分和银行的网站没有任何差别
- 开发者可以在假网站中注入输入事件监听脚本,跨域访问
https://b.com
节点中的内容 - 此时用户的输入都能被监听到,这样假网站就拿到了用户的账号密码
这样一次攻击就完成了
例2:如果ajax可以跨域,就会有以下攻击场景
- 用户在银行网站
https://b.com
进行了登录,网站使用cookie鉴权 - 攻击者直接从网站
https://a.com
发起一个指向银行网站的攻击请求,此跨域请求会携带上目标站点上的cookie - 银行服务端验证用户cookie无误,返回对应的响应数据
- 此时就造成了用户信息泄露,用户是无法感知到的
这样一次攻击就完成了
采用同源策略限制跨域访问,主要就是为了用户信息的安全考虑
跨域
违反同源策略就是跨域
影响
最常见的两种跨域场景就是
- ajax跨域
- iframe跨域
跨域示例
ajax跨域
执行下面代码会在开发者工具中的 Console面板看到以下错误信息
Access to fetch at 'https://ep.sugarat.top/' from origin 'http://127.0.0.1:5500' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
<body> <button id="btn">click me</button> <script> const $btn = document.getElementById('btn') $btn.onclick = function () { fetch('https://ep.sugarat.top/', { method: 'get' }) } </script> </body>
iframe跨域
无法跨域访问iframe中的DOM元素信息
<body> <iframe src="https://sugarat.top/" width="100%" height="1000px" frameborder="0"></iframe> <script> const iframe = document.getElementsByTagName('iframe')[0] console.log(iframe.contentWindow.document.children[0].outerHTML) // <html><head></head><body></body></html> </script> </body>
跨站
Cookie与此息息相关,Cookie实际上遵守的是“同站”策略
什么是同站
只要两个 URL 的 eTLD+1 相同即是同站,不需要考虑协议和端口
eTLD: (effective top-level domain) 有效顶级域名,注册于 Mozilla 维护的公共后缀列表(Public Suffix List)中,如.com
、.co.uk
、.github.io
,.top
等
eTLD+1: 有效顶级域名+二级域名,如 taobao.com
,baidu.com
,sugarat.top
tips: 这里的一级,二级域名主要指计算机网络中规定的,与通常业务开发中所指的一二级域名有些许差异
以当前页面为例:https://sugarat.top/bigWeb/browser/cros.html
- eTLD: .top
- eTLD+1: sugarat.top
URL | 是否同站 | 理由 |
sugarat.top | ✅ | eTLD+1一致 |
ep.sugarat.top | ✅ | eTLD+1一致 |
ep.sugarat.top:8080 | ✅ | eTLD+1一致 |
baidu.com | ❌ | eTLD 不一致 |
只要eTLD+1不同就是跨站
对Cookie的影响
因为Cookie遵循的是同站策略,很多网站都是把一些权限,用户行为,主题,个人的配置信息
所以很多网站会把这些信息存在二级域名下,即让其子域名能够共享这些配置,鉴权信息
以taobao举例
打开 taobao.com
,可以看到其cookie有
我们在 ai.taobao,com
下也可看到这些cookie
预检请求
使用后端开启CORS解决跨域的方式,浏览器会把请求分成两种类型
- 简单请求
- 复杂请求
简单请求
触发简单请求的条件
1.请求方法仅限于:
- GET
- HEAD
- POST
2.Content-Type仅限于:
- text/plain
- multipart/form-data
- application/x-www-form-urlencoded
复杂请求
非简单请求
的即为复杂请求↓
对于复杂请求,首先会发起一个预检请求,请求方法为options
,通过该请求来判断服务器是否允许跨域
与预检请求有关的以Access-Control-
开头的响应头:
- Access-Control-Allow-Methods:表明服务器支持的所有跨域请求的方法
- Access-Control-Allow-Headers:表明服务器支持的头信息
- Access-Control-Max-Age:指定本次预检请求的有效期,单位为秒,在此期间,不用再重新发型新的预检请求