百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术文章 > 正文

30 分钟如何理解CORB是什么(cor是什么意思的缩写)

zhezhongyun 2025-01-31 16:18 23 浏览

写在前面

前些日子在调试 bug 的时候,偶然发现这么一个警告:


Cross-Origin Read Blocking (CORB) blocked cross-origin response https://www.chromium.org/ with MIME type text/html. See https://www.chromestatus.com/feature/5629709824032768 for more details.

我当前的 chrome 版本是 v68,如果是 v66 或更低版本可能提示的警告信息略有不同。印象中只对 CORS 比较熟悉,CORB 是个什么鬼?好奇心迫使我想要了解一下它到底是什么,于是暂时把手头工作放下查了一些资料并花时间汇总了一下,就有了这篇文章。

再介绍 CORB 是什么以及有什么用之前,需要先了解一些背景知识以做铺垫,下面进入正文。

旁路攻击(side-channel attacks)

首先需要了解的是旁路攻击这个术语,关于术语本身的解释,可以去维基百科搜索。简单讲的话,就是从软件系统的物理实现层获取信息进行攻击的手段,软件系统在正常运行时,产生了一些边缘特征,这些特征可以体现一些隐私信息。

这么说可能略显抽象,就拿后文视频链接中列举的例子说明一下,假设小 A 的账户密码是 gyease,小 B 想破解小 A 的密码,他可以这么做:

  • 首先他可以先输入aaaaaa,之后记录一下从点击登录按钮到错误提示的间隔时间(虽然很短,假设有工具可以记录)

  • 之后再输入baaaaa,同样记录时间

  • 重复以上过程直到gaaaaa,会发现从点击登录按钮到错误提示的间隔时间稍微变长了一些

  • 之后小 B 即知道小 A 的密码第一位是g,之后重复以上步骤即可破解小 A 的密码。

当然这里的例子很蠢,而且也过于理想化,但足够说明问题。反应快的读者可能马上就会知道为什么在观察 gaaaaa 的测量结果后小 B 就会知道小 A 首位密码,这是因为执行校验密码是否正确的代码是需要时间的,因此在理想条件下,首位错误和首位正确第二位错误的反馈结果必然是后者时间略长。

    这就是一个比较典型的旁路攻击类型,专业的名称叫做计时攻击(timing attack),有兴趣的可以上网搜索了解详情。

      预执行(speculation execution)

        之后再来了解预执行这个概念,电脑之所以可以执行我们所编写的代码,其背后是由若干硬件协同工作的结果。其中两个比较重要的,一个是内存,一个是CPU。众所周知,CPU执行计算的速度肯定是远大于它读取内存的速度的,这样的结果就是,CPU在对内存读取某些数据的时候,会闲置,这样变造成了浪费。为了提高性能,现代基本大部分硬件制造商都引入了预执行这个机制来压榨CPU的性能。大概的意思如下,比如你写了一段代码:

        逻辑上,这个 if 语句内部的代码是否执行,取决于 somethingTrueOrFalse 变量,但是注意,这是逻辑上的,CPU在运行这段代码的时候,可不是这样子的。它可能会直接跳过判定 somethingTrueOrFalse 是真是假的逻辑,直接执行 if 语句内部的代码,之后反过来再根据 somethingTrueOrFalse 的取值情况作出反应,如果为真,则保留执行结果,如果为假,则撤销执行结果。

        这里对于预执行的描述是极度简化的,不过足够说明概念了。如果有兴趣可以上网搜索相关文章,尤其是预执行策略方面的,我看了一些,没看完,感觉和AI有的一拼(题外话)。

        幽灵和熔断漏洞(Spectre & Meltdown)

        这个漏洞是在今年 1 月份被报道出来的,是硬件系统层面的漏洞。关于这个漏洞本身,网上已经有专业的论文对其进行了详尽的介绍,有兴趣可以自行搜索阅读,这里就不展开说了。简单讲,就是结合上文提及的两个概念的两种实际攻击方法。

        这里还需要再说一下 CPU 读取数据的方式,CPU 除了利用预执行来提供性能,它本身在从内存读取数据的时候,还会涉及一个缓存的概念。从缓存读取数据的速度是大于内存的,当 CPU 发现将要读取的一个数据在缓存中存在时,它会直接从缓存中读取,这样同样可以提高性能,但是缓存很小同时也很昂贵,所以缓存的大小无法与内存相比。同时,每个程序运行时,CPU 为了防止进程间互相保持独立,它们都拥有属于自己的某块内存区域,假设程序 A 存在一条想要直接越界访问程序 B 内存的指令,这在 CPU 是属于非法的,它不会执行这条指令,而会选择抛出异常并终止程序,然后将其相应的内存数据清零。

        之后问题就出现了,假设我们有以下代码:

        这个例子在参考链接的文章中你可能会多次见到,这里大概解释一下:

        • arr1 假设是一个比较小的数组,x 是一个我们定义的索引值变量

        • 正常情况下,如果 x 超过 arr1 的长度,程序是要崩溃的,因为它越界了,但是在预执行的前提下,CPU 可能会忽略越界的问题而执行 if 语句内部的代码

        • arr2 是我们提前声明的一个用来储存数据的数组,它储存于内存的另一个区域,它是连续的,而且我们强制它没有拷贝至缓存,只保存于内存(这点在视频中有提及,我这里强调一下)

        • 之后我们假设 arr1 中的位于 x 索引出的值是 k,那么在预执行的前提下,y=arr2[arr1[x]]等价于y=arr2[k]

        • 然后由于我们会把 arr2[k] 这个值付给另一个变量 y,这里其实算是一个访问值的操作,CPU 后将 arr2[k] 位于内存地址的值转入缓存中,而其余元素保留在内存中(因为并未访问)

        之后,只需要遍历 arr2 这个数组,当发现某个索引上的值的访问速度远快于其他索引的访问速度时,这个索引既是我们从越界内存中“偷”到的值。至此,一次攻击就完成了,理论上,利用这个漏洞,可以获取缓存区所有地址的值,其中很有可能包含敏感信息,比如密码什么的。

        CORB(Cross-Origin Read Blocking)

        说了这么多,终于可以引入正题了。它是什么呢?引入 chromium 文档中关于它的定义:

        这里可能有人会问,这和上面说的一堆又有什么关系呢?是这样的,Chrome浏览器在处理不同 tab 和不同页面时,会将为它们划分不同的进程,而且受制于同源策略的影响,这些页面之间本应该互不干扰。但是我们知道,同源策略虽然牛逼,但浏览器中仍然存在一些不受制于它约束的 api、标签,比如常见的 img、iframe 和 script等等。诸如以下代码,不知道看文章的诸位有没有写过,反正我是写过,或者说遇见过:

        有人可能会问,一个 img 标签你 src 属性不填图片的 uri,你是不是傻。其实不是这样的,有时候对网站做一些跟踪和分析时,确实会这么写,因为浏览器会往 https://foo/bar/baz/这个地址发送一个 GET 资源的请求,在服务端我们可以利用这个请求做一些追踪的逻辑,同理 script 也可以完成需求。但是这么做的后果就是,虽然 img 帮我们发送了这个请求,但是它却没有得到所期望格式的资源,所以这里实际可以算作一种错误或者异常。而一些攻击者可以利用这一点,比如,在页面嵌入下面的代码:

        来加载跨域私密文件,因为 img 不受同源策略的制约,这个请求是可以发出去的,服务器响应返回后,显然 secret.json 不是一个图片格式的资源,img 不会显示它,但是并不代表负责渲染当前页面的进程的内存中没有保留关于 secret.json 的数据。因此攻击者可以利用上文中提及的漏洞,编写一些代码来“偷”这些数据,从而造成安全隐患。

        而 CORB 的作用就是当浏览器尝试以上面代码的方式加载跨域资源时,在资源未被加载之前进行拦截,从而提升攻击者进行幽灵攻击的成本,这里之所以是说提升成本还非彻底解决是因为这个漏洞是基于硬件层面的,所以软件层面只能做有限的修复,有的人可能马上会说,那 CPU 直接去掉或者用户放弃使用预处理功能不就好了吗?理论上是这样的,但是这将导致预处理带来的性能红利瞬间消失,而且 CPU 的架构设计也不是一天两天就能改的,而且就算改了也没办法一下普及。

        哪些内容类型受 CORB 保护

        当前有三种内容类型受保护,分别是 json、html 和 xml。关于如何针对每种内容类型 CORB 如何对其进行保护,文档中有详细的章节进行介绍,这里就不多说了。我浏览了一遍,大体的规则均是对内容格式进行一些有针对性的校验,以确认它确实是某个内容类型。这个校验结果最终影响 CORB 的运作方式。

        CORB 如何运作

        这里我引用文档部分章节并做翻译,关于其中的备注可以直接浏览原文档进行查看。

        CORB 会根据如下步骤来确定是否对 response 进行保护(如果响应的内容格式是 json、html 或者 xml)。

        如果 response 包含 X-Content-Type-Options: nosniff 响应头部,那么如果 Content-Type 是以下几种的话, response 将受 CORB 保护:

        • html mime type

        • xml mime type(除了 image/svg+xml)

        • json mime type

        • text/plain

        • 如果 response 的状态是 206,那么如果 Content-Type 是以下几种的话, response 将受 CORB 保护:

        • html mime type

        • xml mime type(除了 image/svg+xml)

        • json mime type

        • 否则,CORB 将尝试探测 response 的 body:

        • html mime type,并且探测结果是 html 内容格式,response 受 CORB 保护

        • xml mime type(除了 image/svg+xml), 并且探测结果是 xml 内容格式,response 受 CORB 保护

        • json mime type,并且探测结果是 json 内容格式,response 受 CORB 保护

        • text/plain,并且探测结果是 json、html 或者 xml 内容格式,response 受 CORB 保护

        • 任何以 JSON security prefix 开头的 response(除了 text/css)受 CORB 保护

        这里值得一提的是,对于探测是必须的,以防拦截了那些依赖被错误标记的跨源响应的页面(比如,图片资源但是格式却被标记为 text/html)。如果不进行格式探测,那么会有16倍以上的 response 被拦截。

          CORB 如何拦截一个响应

            当一个 response 被 CORB 保护时,它的 body 会被覆盖为空,同时 headers 也会被移除(当前 Chrome 仍然会保留 Access-Control-* 相关的 headers)。关于 CORB 的工作方式,一定要和 CORS 做区分,因为它要防止这些被拦截的数据进入渲染当前页面进程的内存中,所以它一定不会被加载并读取。这不同于 CORS,因为后者会做一些过滤操作,数据虽然不可被加载,但是可能仍然保留在渲染进程的内存中。

            对于其他 web 平台特性的影响

            这里仍然是翻译部分文档中的内容,因为本身写的就很细致了。

            CORB 不会影响以下技术场景:

            1、XHR and fetch()

            CORB 并不会产生显而易见的影响,因为 XHR 和 fetch() 在响应中已经应用了同源策略(比如:CORB 应该仅会拦截那些因缺少 CORS 而发生跨域 XHR 错误的 response)

            2、Prefetch

            CORB 会拦截那些到达跨源渲染进程的 response body,但是不会阻止那些被浏览器进程缓存的 response body(然后传递到另一个同源渲染进程)。

            3、Tracking and reporting

            当前存在各种各样的技术,尝试对记录用户访问的服务器发送 web 请求,以检查用户是否已访问某些内容。该请求经常使用隐藏的 img 标签进行发送(我前文提及了),然后服务器以 204 状态码或者 html 文档进行响应。除了 img,还可以使用类似 script、style 和别的可用标签。

            CORB 不会对这些技术场景造成影响,因为它们不会依赖于服务器返回响应的内容。这一点同样使用与其他类似的技术场景和 web 特性,只要它们不关心响应即可,比如:beacons,ping,CSP违规报告 等。

            4、Service workers

            Service workers 可以拦截跨源 requests 并在其内部人为地构建 response(没有跨源和安全边界),CORB 不会拦截它们。

            当 Service workers 确实缓存了一些跨源的 responses 时,由于这些 responses 对于调用者来讲是透明的,因此 CORB 会拦截它们,但是这并不需要对 Service Worker 作出任何改变。

            5、Blob and File API

            即使没有 CORB 的话,获取跨源的 blob URLs 当前也会被拦截。

            Content scripts and plugins

            它们所属的范围并不含在 CORB 的职责内 —— CORB 假设已经有某种合适的安全策略或安全机制存在于这些 content scripts 和 plugins 中(比如 Adobe Flash 已经实现了类似 CORB 的机制,通过 crossdomain.xml)。

          总结

            大概就这么多,读到这里,应该对 CORB 能够有一个初步的认识和把握了,以及它所需要解决的问题。最后我列举了我写这篇文章之前阅读的文章或者视频,有些需要自备梯子,有些不要。尤其推荐那个 B 站的视频,算是讲的最生动形象的了。另外 Chrome 的文档也很详细,只是有些长,需要耐心慢慢读完。

          以上,如有错误,还望指出,大神轻喷。

            编辑:千锋HTML5

            作者:littleLyon

            https://fanmingfei.com/posts/Animation_Base.htm

              相关推荐

              字体缩放(方式一)(字体缩放150%怎么做)

              通过元素宽度和字数计算得到缩放简单实现如下:/***字体最大为视觉要求大小(maxFontSize);超出缩小字体显示,最小为minFontSize;最小字体时超出部分使用圆点(...);*p...

              网页世界隐藏的神秘代码语言,竟能这样改变布局

              CSS基础:选择器与属性CSS(CascadingStyleSheets)是用于控制网页外观的一门样式表语言。它通过定义HTML元素的显示方式来增强网页的表现力。CSS的选择器允许开发者精确地定位...

              CSS属性值计算过程详解(css属性用来定义元素计算)

              在CSS中,即使某些属性没有显式声明,浏览器也会通过**属性值计算过程**为每个元素的所有属性赋予最终值。这一过程分为四个关键步骤,以下将逐一解析。1.确定声明值浏览器首先检查所有**直接应用**到...

              软网推荐:找回调整Windows 10字号功能

              之前的系统,从WindowsXP到早期版本的Windows10,均有字体大小调整功能,但从创意者版Windows10以来,取消了之前的设置选项,取而代之的是自定义缩放比例设置。使用这个功能调整过...

              Excel中如何设置文本框属性,实例代码讲解

              Excel不仅可以对数据进行处理,而且也可以图形化数据,直观显示数据表达的内容。本节介绍一个很重要的对象,Characters,字符对象,使用Characters对象可修改包含在全文本字符串中的任...

              CSS 字体样式(css中字体)

              本节我们来讲字体样式,之前我们学习HTML的时候学过一些用于字体加粗、倾斜的标签,但是使用标签来实现的效果肯定没有我们通过CSS中的样式来的方便。接下来我们会给大家介绍下面这几个属性的使用:通...

              PC网站建设必备代码知识:HTML基础与应用技巧

              在PC网站建设的相关课程里,代码扮演着至关重要的角色。只有熟练运用正确的代码,我们才能打造出功能完善、用户体验出色的PC网站。接下来,我会详细讲解在PC网站建设环节中必须了解的代码知识。HTML基础代...

              让你大跌眼镜的疯狂 HTML 和 CSS 技巧

              今天,分享一个让你大开眼界的技巧。通过使用这个技巧,你可以将整个网页变成一个CSS编辑器。没错,你从未见过这种方法。当我第一次尝试时,我完全被震惊到了。现在,让我们开始吧!步骤1首先,创建一个基础的...

              jQuery EasyUI使用教程:创建一个链接按钮

              jQueryEasyUI最新版下载>本教程主要为大家展示如何使用jQueryEasyUI创建一个链接按钮。通常情况下,使用“button/”元素来创建一个按钮;使用“a/”元素来创建链接按钮...

              React 19 有哪些新特性?(react100)

              如果你对React18还不熟悉,欢迎阅读之前的文章《React18全览[1]》最近React发布了V19RC版本,按照惯例,我们对React19的新特性进行一次深度的体验学习...

              Java注解探秘:为什么@PostConstruct能解决你的初始化难题?

              你是否在Spring项目中遇到过这样的困扰:明明依赖注入已经完成,但某些配置就是无法正常加载?手动调用初始化方法又容易引发空指针异常?这就是@PostConstruct注解大显身手的时候了!@Post...

              AI驱动的表单自动填写(ai置入表格)

              我们都同意,填写表格是一项枯燥且耗时的任务。如果我们可以创建一个可以为我们填写表格的AI助手,让我们将时间投入到更有建设性的任务中,那会怎样?AI助手将能够通过调用以表单字段为参数的函数来填写表...

              从零到一:小程序设计新手如何快速上手?

              开发环境搭建对于小程序设计新手而言,搭建合适的开发环境是首要任务。以小程序为例,其官方提供了功能强大的开发工具——开发者工具。首先,新手需前往官方开发者平台,在页面中找到“工具下载”板块,根据...

              JavaSwingGUI从小白到大神-6(续)(java从小白到大牛怎么样)

              接上一篇《JavaSwingGUI从小白到大神-6》,因本篇文章3万多字,头条一篇发不完,只能分开发。同事查询面板:CompanyFind.javapublicclassCompanyFind{...

              C# winform界面假死(c#程序假死)

              针对C#WinForm界面假死问题,以下是分步解决方案:1.使用异步编程(async/await)将耗时操作移至后台线程,保持UI线程响应。步骤:将事件处理函数标记为async。使用Task....