RIVALSA网络日志

Rivalsa周记(第21周):子资源完整性校验

于2021-09-26发布

我开始收信件了

之前,我公开的联系方式仅限于工单系统和邮箱,且以工单系统为主,但现在我又公开了一种新的联系方式,那就是邮寄信件。

我的一位朋友是无线电爱好者(BG2KSI),为了方便交换 QSL 卡片就在邮局租用了一个信箱。最近,我突然想到,我也可以利用一下他的信箱呢,这样我就也有了一个可以公开的收信地址了,联系我也更方便了。

我的收件地址展示在联系我们页面的信件部分,欢迎来信。

最后,我在替中国邮政宣传一下:中国境内邮寄信件每20克需要1.2元的邮资,不足20克的部分按20克计算,如果需要挂号,则另加3元邮资。我常用的信封在邮局的售价为0.1元/个,邮票可以直接在邮局购买,如果想更便宜,可以上网找找打折邮票。(如果与您当地情况不一致,请以当地官方公布信息为准。)

teambition 网盘即将下线

9月17日,我收到了 teambition 网盘发来的短信,内容如下。

【Teambition】因业务方向调整,Teambition「网盘」服务将在 2021 年 9 月 30 日下线。请尽快将个人文件下载到本地或迁移到本团队设计研发的「阿里云盘」,我们提供在线快速搬迁方案,点击了解:(网页链接) 回复TD退订

在阿里刚开始做网盘的时候是将网盘功能放在 teambition 中的,当时我就觉得不是很方便,不过一直用着。后来又上线了阿里云盘,就感觉用起来非常方便了,于是乎将 teambition 中的资料转移到了阿里云盘中。而我的 teambition 网盘一直在闲置,所以 teambition 网盘下线对我并没什么影响。

不过如果您在 teambition 网盘中还有资料,您可以按照官方的指引将 teambition 网盘的文件迁移至阿里云盘。

HTML知识点(三):子资源完整性校验

原本想每周都要发布 HTML 知识点的,没想到刚写两次就又没得写了,每周都为写什么知识点而头疼,所以从本周开始,改为不定期发布。

P.S.希望不要走之前 TCP/IP 专题的老路。

基本概念

在写前端页面时,经常需要引入外部资源,但我们如何保证实际被引入的资源就是我想想要引入的资源的?如果被引入资源的网站是由我们信任的人控制的,那么 HTTPS 就能有效地解决这个问题,因为 HTTPS 保证了数据在传输的过程中不被窃听和篡改。但如果被引入的资源还要经过一个中间服务(比如 CDN),这时为了使用 HTTPS 我们必须把私钥交给中间服务者,所以中间服务者完全有能力篡改被引入的资源而不被我们知道。

子资源完整性(Subresource Integrity, SRI)校验正是用来解决这个问题的。在引入资源的同时,通过 integrity 属性告知被引入资源的散列值,然后引入资源后,按照同样的算法计算资源的散列值,若与 integrity 属性值相同,就能说明被引入资源未被篡改,否则,浏览器将拒绝对应的外部资源。

目前 SRI 支持的散列算法仅包括 sha256、sha384 和 sha512

目前仅 script 标签和 link 标签支持 integrity 属性

生成被引入资源的散列值

被引入资源的散列值需要以二进制形式表示,并进行 base64 编码。可以利用 openssl 工具,在命令行中执行如下命令:

openssl dgst -sha384 -binary FILENAME | openssl base64 -A

其中 -sha384 可以替换为支持的其他散列算法,FILENAME 为被引入资源的文件地址。

或者,也可以利用 SRI Hash Generator 这个工具直接生成对应的标签。

例子

在某站点(在本例中视为 http://localhost/)的根目录下新建文件 index.html,并写入以下代码:

在同一个目录下建立文件 sri.js,并写入以下代码:

document.getElementsByTagName('p')[0].innerText = 'Script execution succeeded';

在浏览器中访问 http://localhost/index.html,可以看到页面中显示 Script execution succeeded,表示脚本执行成功。这是我们在没有应用 SRI 的情况下,可以正常执行脚本。接下来,在网站根目录下利用 openssl 工具计算 sri.js 的哈希值。在命令行中执行如下命令:

openssl dgst -sha512 -binary sri.js | openssl base64 -A

可以得到如下散列值:

6Vu0FOdc1Pt1XrFMUOySXiNqzyGBjZ1n8Bjp1qVaWhL5FmN8RozRzRiuaGlqBe4rcF7gyN9DVmHWkIRJBlFmSQ==

然后,修改 index.html 的代码为以下内容:

其中 integrity 的属性值分为两部分,第一部分为散列算法名称,第二部分散列值,两部分直接用减号(-)分隔。

在浏览器中访问 http://localhost/index.html,可以看到页面中仍然显示 Script execution succeeded,表示当散列值一致时脚本同样可以执行成功。

一旦将脚本的内容更改,比如在 sri.js 中 Script execution succeeded 后面加一个感叹号。这时再在浏览器中访问 http://localhost/index.html,可以看到页面显示的是 Hello world,浏览器拒绝执行了这个脚本。

跨域的情况

上面例子中,我们考虑的是同源的情况,如果被引入资源是跨域的(协议、域名和端口号任意一个或多个与本页面的不一致,则为跨域),还需要在加上 crossorigin,值为 anonymous 或者不带属性值,因为 crossorigin 属性无属性值或者属性值无效时,就会按照 anonymous 处理。

假如上面例子中的 index.html 文件位于 http://localhost/,而 sri.js 位于 http://localhost:81/ 则 index.html 中的代码应修改为:

或者

同时,在 http://localhost:81/sri.js 的响应头中,也需要添加对应的 CORS 字段。关于 CORS 的相关内容,请参阅《如何通过 CORS 解决跨域问题》

强制 SRI 验证

可以通过配置内容安全策略(Content Security Policy, CSP)来强制进行 SRI 验证。

如果在响应的 HTML 页面的 HTTP header 中包含如下内容,则所有脚本必须有 integrity 属性且通过验证才能被加载。

Content-Security-Policy:require-sri-for script;

如果在响应的 HTML 页面的 HTTP header 中包含如下内容,则所有样式表必须有 integrity 属性且通过验证才能被加载。

Content-Security-Policy:require-sri-for style;

当然,也可以同时包含以上两条内容。

结束语

从下一篇周记开始,就不写结束语了吧。

(正文完)

版权信息

本作品著作权归属 Rivalsa 所有,除非 Rivalsa 明确许可您使用,否则任何个人或组织不得以任何方式直接或间接的复制、伪造、转载、摘编、翻印、改编、演出或以其他方式使用本作品。

已获得1个赞0个差评

3条评论

头像

林林 - 2021-09-27 18:40:17   举报  回复

还有你这个安全验证好像挺特别,框跟QQ的有点像,但是题目好像有点难。感觉这样机器是不会破解的。每次都问法都不一样。

头像

Rivalsa 博主 - 2021-09-27 20:00:53   举报

哈哈,你说的对,就是调用的腾讯的产品,我为这个验证码付了不少钱呢。

头像

林林 - 2021-09-27 18:39:31   举报  回复

阿里云盘听说很好用,但我现在基本不用云盘了。

发表评论(取消回复)

通知选项

确定

是否 AT 其他评论者

不 AT 任何人