了不起的Chrome浏览器(5):Chrome 93支持Error Cause,我国首个ECMAScript提案可以用了

摘要: Chrome 93带来了哪些有意思的新特性呢?

背景

十多年来,Web技术突飞猛进,其中Chrome功不可没,了解Chrome可以帮助我们理解整个行业的发展趋势。

因此,我将以《了不起的Chrome浏览器》为题,对Chrome的每一个版本的重要特性进行详细解读,同时分享一些自己的一些思考:

通过专注于Chrome的写作,既可以可以提高我的专业能力,也可以提高个人影响力。我的长期目标是在2025年出版一本关于Chrome的书,毕竟出版自己的书每一个写作者最高的追求。

我是寒雁,一个热爱写代码和写文章的程序员,欢迎关注我的微信公众号寒雁Talk

TL;TR

详细解读

Error Cause

Chrome 93支持了Error Cause,支持在新建Error时配置cause参数,这样可以帮助我们更好的进行异常处理:

try {
return await fetch("//unintelligible-url-a") // 抛出一个 low level 错误
.catch((err) => {
throw new Error("Download raw resource failed", { cause: err }); // 将 low level 错误包装成一个 high level、易懂的错误
});
} catch (err) {
console.log(err); // Error: Download raw resource failed
console.log("Caused by", err.cause); // Caused by TypeError: Failed to fetch
}

Error Cause提案由阿里巴巴的昭朗同学负责,从去年9月份开始,到今年3月份进入Stage 3,再到现在Chrome支持,整个推进速度还是蛮快的。

再次恭喜昭朗同学,这是我国首个进入Stage 3的EcmaScript提案!

Error Cause提案本身很简单,但是它的价值还是蛮大的,社区类似的解决方案@netflix/nerror的周下载量高达10万。

但是,如何在一个国际化的标准组织推动一个提案,可不是一件简单的事情,需要耗费不少的时间和精力。

作为一个程序员,能够让编程语言变得更好,是一件挺有价值的事情,感兴趣的同学赶紧行动起来吧!

Object.hasOwn

Chrome 93新增了Object.hasOwn方法,用于判断Object是否存在某个属性:

const obj = { name: "test" };
console.log(Object.hasOwn(obj, "name")); //true

不是有了Object.prototype.hasOwnProperty么?有啥区别?

const obj = { name: "test" };

// 直接调用
console.log(obj.hasOwnProperty("name")); //true

// 通过call方法调用
console.log(Object.prototype.hasOwnProperty.call(obj, "name")); //true

hasOwnProperty的函数名有点冗长,社区还有一个npm包has来解决这个问题,其周下载量高达2200万。hasOwn比hasOwnProperty更短,这会让它得到大家更加偏爱,不过这倒不是问题的关键。

hasOwnProperty是通过propertype继承的方法,可以被重写,这会导致结果错误:

let foo = {
hasOwnProperty: function () {
return false;
},
bar: "Here be dragons",
};

foo.hasOwnProperty("bar"); // false

ESLint的no-prototype-builtins规则就是为了避免这个问题,禁止调用Object.prototype所继承的方法。

hasOwn是Object的静态方法,其实还是可以通过Object.defineProperty重写,这就有点尴尬了…

Block ports 989 and 990

为了防止ALPACA攻击,Chrome 93屏蔽了989和990端口,即FTPS协议所使用的端口

ALPACA攻击由一些德国科学家所发现,今年6月份才公开,是一种非常巧妙地跨应用层网络协议的攻击方式,利用了同一个TLS证书被多个不同协议的服务复用的问题。

ALPACA攻击的详细过程如下图:


图片来源:ALPACA Attack

<!-- 代码来源:https://github.com/RUB-NDS/alpaca-code/blob/master/testlab/servers/files/nginx-attacker/html/upload/ftps.html -->
<script>
var formData = new FormData();
formData.append("a", "USER bob"); // FTP用户名
formData.append("b", "PASS 12345"); // FTP密码
formData.append("b", "TYPE I"); // 二进制模式
formData.append("c", "PASV"); // 被动模式
formData.append("d", "STOR leak"); // FTP上传命令

var xhr = new XMLHttpRequest();
xhr.open("POST", "https://target.com");
xhr.send(formData);

setTimeout(function() {
window.location = "https://target.com";
}, 5000);
</script>

看起来挺可怕的,但是实际上还好,因为实施ALPACA Attack的前提条件挺多的,还是以Upload Attack为例:

  • 同一个TLS证书被多个服务共用,这个条件还是相对容易满足,因为运维为了省事嘛,我也挺喜欢通配符证书的,可惜当时Let’s Encrypt还不支持所以没用过,以后也不敢用了;
  • 黑客能够实施CSRF攻击,这个正确配置same-site就可以杜绝了;
  • 被攻击的HTTPS服务使用是HTTP/1.1及以下版本,因为较新的Chrome、Firefox、Edge浏览器只支持通过ALPN(Application-Layer Protocol Negotiation)建立HTTP/2连接,必须指定应用层协议,也就没法搞跨协议攻击了;
  • 黑客拥有FTP服务的账号密码;
  • 黑客可以实施中间人攻击,这是最难的一点,需要入侵网络中的节点,内网稍微简单一点;

因为实施这一攻击的前提条件比较多,所以它更多的是一种理论上的攻击方式,不必过于担心。虽然说ALPACA Attack实际威胁不大,但是它所发现的问题还是很有价值的,它发现了看似牢不可破的TLS的隐藏漏洞:同一个证书被多个不同应用层协议共用以及不保护IP和端口。目前来看,最好的预防方式是不要跨协议共享TLS证书,同时启用ALPN。

至今,Chrome已经累计屏蔽了13个端口,见下表:

日期Chrome版本屏蔽端口目的详情
2021-08-31Chrome 93989、990阻止ALPACA攻击Feature: Block ports 989 and 990
2021-05-25Chrome 9110080阻止NAT Slipstream 2.0攻击Feature: Block HTTP port 10080
2021-04-14Chrome 90554阻止NAT Slipstream 2.0攻击Feature: Block HTTP port 554
2020-11-17Chrome 875060、5061阻止NAT Slipstream攻击Feature: Block HTTP ports 5060 and 5061
69、137、161、 1719、1720、1723、6566阻止NAT Slipstream 2.0攻击Feature: Block HTTP ports 69, 137, 161, 1719, 1720, 1723, and 6566

所以大家以后看到哪个端口不能再用了,不要感觉奇怪。道高一尺魔高一丈,目测被屏蔽的端口会越来越多。再这样搞下去,是不是只有443端口能用了?

Remove 3DES in TLS

为了预防Sweet32攻击和Lucky Thirteen攻击,Chrome 93移除了对TLS_RSA_WITH_3DES_EDE_CBC_SHA密码套件的支持。

TLS_RSA_WITH_3DES_EDE_CBC_SHA密码套件的名字很长,其中3DES和CBC代表对称加密算法,它在2016年被证明可以被Sweet32攻击。

我们不妨重点分析一下Sweet32攻击是怎么回事。

3DES是对称加密算法( symmetric encryption),同时也是分块加密算法(block cipher)。它会将需要加密的文本切分为64位的文本块,然后对每一块进行加密。

由于3DES算法的分块长度只有64比特(更安全的AES算法的分块长度是128比特),因此它容易受到生日攻击(birthday attack)。

生日攻击(birthday attack)的原理来源于生日悖论(birthday paradox):

在不少于23 个人中,至少有两人生日相同的概率大于50%。 例如在一个30 人的小学班级中,存在两人生日相同的概率为70%。 对于60 人的大班,这种概率要大于99%。

生日悖论并不是真正的悖论,通过简单的概率公式就能算出来,它只是违反了我们的直觉,因此被称为”悖论”。

基于生日悖论,可以推导出(此处忽略推导过程),只要收集足够多的3DES加密块,其中必定会出现完全相同的3DES加密块。

另外,由于CBC加密算法可以被碰撞攻击(collision attack)。只要找到相同的3DES加密块,就可以根据部分已知明文通信内容恢复部分未知的加密通信内容比如Cookie(此处再次忽略推导过程)。

因此,黑客所要做的事情,就是发起CSRF攻击,重复发送大量HTTPS请求,JavaScript代码如下:

// 代码来源:https://sweet32.info/
var url = "https://10.0.0.1/index.html";
var xhr = new XMLHttpRequest();

// Expand URL to ~4kB using a query string
// Alternatively, force a large cookie
url += "?";
var x = 10000000;
for (var i = 0; i <= 500; i++) {
url += x++;
}

while (true) {
xhr.open("HEAD", url, false);
xhr.withCredentials = true;
xhr.send();
xhr.abort();
}

然后,黑客进行抓包,并找到相互冲突的3DES加密块。找到足够多的冲突,就可以恢复Cookie了。

WebOTP API: cross-device support

Chrome 93更新了WebOTP API,支持跨设备。这里所谓的跨设备,指的是安卓端和PC端的Chrome浏览器。

当你的安卓端和PC端的Chrome浏览器都登录了同一个Google账号,安卓手机收到短信验证码之后,不再需要在PC端手动输入了,在手机端直接提交即可:

视频来源:Verify a phone number on desktop using WebOTP API

WebOTP这个名字有点奇怪,其中OTP是one-time-passwords的缩写,指的就是手机的短信验证码。对于很多iOS和安卓APP,我们已经不再需要手动复制粘贴验证码了,APP可以自动识别和提取验证码,我们只需要轻点一下即可。WebOTP就是为了给Web应用带来相同的体验。

如下图,Web应用可以通过navigator.credentials.get获取OTP,当收到短信验证码时,Chrome则可以自动匹配对应域名的OTP,用户确认之后则可以直接验证OTP,不再需要手动复制粘贴验证码,其流程如下图:


图片来源:Verify phone numbers on the web with the WebOTP API

WebOTP API是去年Chrome 84新增的,并且支持在跨域的iframe中使用:

日期Chrome版本说明详情
2021-08-31Chrome 93WebOTP API支持跨设备Feature: WebOTP API: cross-device support
2021-05-25Chrome 91支持在跨域的iframe中使用WebOTP APIFeature: WebOTP API: cross-origin iframe support
2020-07-14Chrome 84新增WebOTP API,用于自动提取手机短信验证码Feature: WebOTP

Feature: Clipboard API: Svg

Chrome 93更新了Clipboard API,支持SVG格式。这一特性,有望用于图片相关的应用(比如:Inkscape, Adobe Illustrator,Figma、Photopea)。

Clipboard API可以用于剪贴板的读写,支持异步比同步接口document.execCommand的性能更好、基于permission API的权限控制更安全。

Clipboard API是2018年Chrome 66新增,目前已经支持图片、HTML、文件等多种格式,功能越来越强大:

日期Chrome版本说明详情
2021-09-21Chrome 94Clipboard API支持从剪贴板读取保留metadata的原始PNG文件Feature: Clipboard: Preserve PNG metadata
2021-08-31Chrome 93Clipboard API支持复制粘贴SVGFeature: Clipboard API: Svg
2021-05-25Chrome 91Clipboard API支持从剪贴板读取只读文件Feature: Clipboard: read-only files support
2020-10-06Chrome 86Clipboard API支持复制粘贴HTMLFeature: text/html support for async clipboard api
2020-08-25Chrome 85Clipboard API支持feature policy(即permission policy)Feature: Feature Policy for Clipboard API
2019-07-30Chrome 76Clipboard API支持复制粘贴图片Feature: Async Clipboard: Read and Write Images
2018-04-17Chrome 66新增异步Clipboard APIFeature: Asynchronous Clipboard API

总结

本篇是《了不起的Chrome浏览器》的第5篇,凑满5篇就可以召唤神龙了?

其实,我2年前还写过一个《JavaScript深入浅出》系列,不过后来因为工作的巨大变动(详见:从创业者到打工人,我在阿里这1年)放弃了:

所以,当我开始写《了不起的Chrome浏览器》时,我也挺担心自己会再次放弃,现在写到第5篇,这样的担心越来越少了:

  • Chrome每个月更新一个版本,每个月写一篇博客,这个写作节奏不紧不慢;
  • Chrome的文档、博客质量非常高,所以我不用担心没有内容可以写,这为我省去了一半的时间;
  • 作为一个写了6年博客的老司机,写博客对我来说挺简单的,也很喜欢;
  • 每篇博客至少要花10个小时,80%的时间是在看博客、论文、视频等参考资料,每次都能学到一些新的知识点;
  • Flag已经立了,2025年要出版一本关于Chrome的书,那就得做到啊;

所以,《了不起的Chrome浏览器》我还是会写下去的!

欢迎关注寒雁Talk公众号,关注《了不起的Chrome浏览器》系列博客,与我一起见证大前端的星辰大海!

参考资料

招聘

阿里巴巴业务平台事业部长期招聘P6及以上前端大佬,参与建设最前沿的阿里前端生态系统,推动行业技术发展,内推地址:hanyan.lk@alibaba-inc.com

欢迎大家关注我的微信公众号寒雁Talk

hanyan_talk

关于Fundebug

Fundebug专注于JavaScript、微信小程序、微信小游戏、支付宝小程序、React Native、Node.js和Java线上应用实时BUG监控。 自从2016年双十一正式上线,Fundebug累计处理了30亿+错误事件,付费客户有阳光保险、达令家、核桃编程、荔枝FM、微脉等众多品牌企业。欢迎大家免费试用




您的用户遇到BUG了吗?

体验Demo 免费使用