关于CORB解决报错原因:
localhost/:12 Cross-Origin Read Blocking (CORB) blocked cross-origin response https://c.y.qq.com/v8/fcg-bin/v8.fcg?g_tk=976692372&inCharset=utf-8&outCharset=utf-8¬ice=0&format=json&channel=singer&page=list&key=all_all_all&pagesize=100&pagenum=1&hostUin=0&needNewCode=0&platform=yqq with MIME type text/html. See https://www.chromestatus.com/feature/5629709824032768 for more details.
1.什么是CORB(Cross-Origin Read Blocking)
CORB(Cross-Origin Read Blocking)是一种判断是否要在跨站资源数据到达页面之前阻断其到达当前站点进程中的算法,降低了敏感数据暴露的风险。
2.Chrome 浏览器行为
CORB 启动时,虽然响应结果会被置空,但是请求的服务仍然成功,`status: 200`。比如:使用 `img` 标签上报页面监控数据,尽管响应结果为空,但请求依旧发送成功,服务器亦正常响应。
3.为什么会有 CORB
简单来说,就是出现了一些网络安全漏洞,为防止漏洞肆虐,便出现了站点隔离(Site Isolation),CORB 则是其中的一种实现策略。
4.幽灵和熔断漏洞(Spectre & Meltdown)
这个漏洞是在今年 1 月份被报道出来的,是硬件系统层面的漏洞。关于这个漏洞本身,网上已经有专业的论文对其进行了详尽的介绍,有兴趣可以自行搜索阅读,这里就不展开说了。简单讲,就是结合上文提及的两个概念的两种实际攻击方法。
这里还需要再说一下 CPU 读取数据的方式,CPU 除了利用预执行来提供性能,它本身在从内存读取数据的时候,还会涉及一个缓存的概念。从缓存读取数据的速度是大于内存的,当 CPU 发现将要读取的一个数据在缓存中存在时,它会直接从缓存中读取,这样同样可以提高性能,但是缓存很小同时也很昂贵,所以缓存的大小无法与内存相比。同时,每个程序运行时,CPU 为了防止进程间互相保持独立,它们都拥有属于自己的某块内存区域,假设程序 A 存在一条想要直接越界访问程序 B 内存的指令,这在 CPU 是属于非法的,它不会执行这条指令,而会选择抛出异常并终止程序,然后将其相应的内存数据清零。
之后问题就出现了,假设我们有以下代码:
if (x < arr1.length) {
y = arr2[arr1[x]]
}
这里大概解释一下:
- arr1 假设是一个比较小的数组,x 是一个我们定义的索引值变量
- 正常情况下,如果 x 超过 arr1 的长度,程序是要崩溃的,因为它越界了,但是在预执行的前提下,CPU 可能会忽略越界的问题而执行 if 语句内部的代码
- arr2 是我们提前声明的一个用来储存数据的数组,它储存于内存的另一个区域,它是连续的,而且我们强制它没有拷贝至缓存,只保存于内存(这点在视频中有提及,我这里强调一下)
- 之后我们假设 arr1 中的位于 x 索引出的值是 k,那么在预执行的前提下,
y = arr2[arr1[x]]
等价于y = arr2[k]
- 然后由于我们会把 arr2[k] 这个值付给另一个变量 y,这里其实算是一个访问值的操作,CPU 后将 arr2[k] 位于内存地址的值转入缓存中,而其余元素保留在内存中(因为并未访问)
之后,只需要遍历 arr2 这个数组,当发现某个索引上的值的访问速度远快于其他索引的访问速度时,这个索引既是我们从越界内存中“偷”到的值。至此,一次攻击就完成了,理论上,利用这个漏洞,可以获取缓存区所有地址的值,其中很有可能包含敏感信息,比如密码什么的。
5.详细介绍CORB(Cross-Origin Read Blocking)
这里可能有人会问,这和上面说的一堆又有什么关系呢?是这样的,Chrome浏览器在处理不同 tab 和不同页面时,会将为它们划分不同的进程,而且受制于同源策略的影响,这些页面之间本应该互不干扰。但是我们知道,同源策略虽然牛逼,但浏览器中仍然存在一些不受制于它约束的 api、标签,比如常见的 img、iframe 和 script等等。诸如以下代码,不知道看文章的诸位有没有写过,或者说遇见过:
<img src="https://foo/bar/baz/">
那肯定有人又会问,一个 img 标签你 src 属性不填图片的 uri,你是不是傻。其实不是这样的,有时候对网站做一些跟踪和分析时,确实会这么写,因为浏览器会往https://foo/bar/baz/
这个地址发送一个 GET 资源的请求,在服务端我们可以利用这个请求做一些追踪的逻辑,同理 script 也可以完成需求。但是这么做的后果就是,虽然 img 帮我们发送了这个请求,但是它却没有得到所期望格式的资源,所以这里实际可以算作一种错误或者异常。而一些攻击者可以利用这一点,比如,在页面嵌入下面的代码:
<img src="https://example.com/secret.json">
来加载跨域私密文件,因为 img 不受同源策略的制约,这个请求是可以发出去的,服务器响应返回后,显然 secret.json 不是一个图片格式的资源,img 不会显示它,但是并不代表负责渲染当前页面的进程的内存中没有保留关于 secret.json 的数据。因此攻击者可以利用上文中提及的漏洞,编写一些代码来“偷”这些数据,从而造成安全隐患。
而 CORB 的作用就是当浏览器尝试以上面代码的方式加载跨域资源时,在资源未被加载之前进行拦截,从而提升攻击者进行幽灵攻击的成本,这里之所以是说提升成本还非彻底解决是因为这个漏洞是基于硬件层面的,所以软件层面只能做有限的修复,有的人可能马上会说,那 CPU 直接去掉或者用户放弃使用预处理功能不就好了吗?理论上是这样的,但是这将导致预处理带来的性能红利瞬间消失,而且 CPU 的架构设计也不是一天两天就能改的,而且就算改了也没办法一下普及。
6.哪些内容类型受 CORB 保护
当前有三种内容类型受保护,分别是 json、html 和 xml。关于如何针对每种内容类型 CORB 如何对其进行保护,文档中有详细的章节进行介绍,这里就不多说了。我浏览了一遍,大体的规则均是对内容格式进行一些有针对性的校验,以确认它确实是某个内容类型。这个校验结果最终影响 CORB 的运作方式。
7.如何解决上面的CORB报错
可以使用后端代理的方式进行处理:
- 在后端使用http请求库对相应的资源进行请求,此时要设置请求头的reffer和host属性为请求的资源的URI
# 定义一个请求头 headers = { "user-agent": "Mozilla/5.0 (Linux; Android 5.0; SM-G900P Build/LRX21T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Mobile Safari/537.36", "referer": "https://c.y.qq.com", "host": "c.y.qq.com" }
- 然后在视图函数中请求资源
def getSingerList(request): url = "https://c.y.qq.com/v8/fcg-bin/v8.fcg?g_tk=976692372&inCharset=utf-等等" res = requests.get(url, params=None, headers=headers) return JsonResponse(json.loads(res.text), safe=False,json_dumps_params={'ensure_ascii':False})
- 接下来参考这篇文章,设置跨域问题,传送门,设置完后就可以在前端发送ajxa请求,请求数据。此时reffer和host虽然是本地的,但是已经可以请求了,这是因为django发送的请求的reffer和host是https://c.y.qq.com(你请求资源的URI)