使用nodejs验证文件的完整性
#javascript #node #cryptography

在使用CDN的第三方JavaScript或CSS库时,您可能会在scriptlink标签上遇到integrity属性。

<script 
  src="https://code.jquery.com/jquery-3.6.4.min.js" 
  integrity="sha256-oP6HI9z1XaZNBrJURtCoUT5SUnxFr8s3BzRl+cbzUq8=" 
  crossorigin="anonymous">
</script>

如果您到现在还没有研究它们,那么您就在正确的位置。

中间攻击

可以修改通过Internet的任何数据直到到达我们的机器上。攻击者可能会使用诸如network eavesdropping之类的技术拦截您和服务器之间的请求和响应,并可能在收到文件之前操纵该文件。

我们需要一种方法来验证我们收到的文件尚未被纠正。

浏览器中的子资源完整性

浏览器实现了一个名为Subresource Integrity(SRI)的安全功能,以验证他们获取并执行的资源的完整性。

您看到的垃圾字符串是您所看到的字符串,因为integrity属性的值是Base64解码加密材料消化,该摘要通过将特定的hash algorithm应用于文件的内容而形成。

如果文件中的任何字符更改,则计算出的哈希也将更改,因此完整性验证将失败,因此浏览器将知道文件已被逐渐缓解。

如果浏览器无法验证要请求的文件的完整性,它们将显示与此类似的错误消息:

Failed to find a valid digest in the 'integrity' attribute 
for resource '<resource-name>' with computed SHA-256 integrity '<calculated-hash>'. 
The resource has been blocked.

用nodejs执行完整性检查

要展示一些演示如何实现此检查,我将使用NodeJS's koude4 module。我们将使用您在第一段中看到的相同的jquery文件。我将将该文件下载到我的计算机中以稍后进行修改。

让我们创建一个index.js文件,然后导入fscrypto模块:

import crypto from 'crypto';
import fs from 'fs';

我们需要fs模块来读取要验证完整性的文件的内容。让我们声明资源名称和预期完整性:

const resource = 'jquery-3.6.4.min.js';
const expectedIntegrity = 'oP6HI9z1XaZNBrJURtCoUT5SUnxFr8s3BzRl+cbzUq8=';

请注意,sha256integrity属性的值面前只是该哈希的名称,该哈希算法已计算出来,因此我们在比较时跳过它。

让我们阅读文件内容并使用sha256算法计算摘要:

const jquerySource = fs.readFileSync(resource);
const digest = crypto
  .createHash('sha256')
  .update(jquerySource, 'utf8')
  .digest();

const calculatedIntegrity = digest.toString('base64');

digest变量的值是一种称为Buffer的类型,它只是一个字节,因此我们需要将其转换为base64编码中的字符串。

最后,我们只需要将calculatedIntegrityexpectedIntegrity进行比较,如果它们是相等的,那么jquery-3.6.4.min.js尚未被调整,如果没有,则意味着文件内发生了变化:

if (calculatedIntegrity == expectedIntegrity) {
  console.log('✔️ Resource integrity verified!');
} else {
  console.log(`❌ Failed to find a valid digest in the 'integrity' attribute 
  for resource '${resource}' with computed SHA-256 integrity '${calculatedIntegrity}'.`);
}

如果使用node index.js运行此代码,则可能会看到此输出:

$ node index.js
✔️ Resource integrity verified!

现在,如果更改jquery-3.6.4.min.js文件的内容,然后再次运行代码,那么您将看到与此类似的输出:

$ echo 'some malicious code' >> jquery-3.6.4.min.js
$ node index.js
❌ Failed to find a valid digest in the 'integrity' attribute 
  for resource 'jquery-3.6.4.min.js' with computed SHA-256 integrity '+FiqKbj0h12Db1PZj62G+h2BMtOueBg26YQOJFY+6wg='.

结论

我希望这篇文章对您有帮助,建议您在article at Smashing Magazine about Subresource Integrity阅读更多并分享您的想法。

您可以看到我们在my GitLab repository上写的代码的完整版本。