在使用CDN的第三方JavaScript或CSS库时,您可能会在script
或link
标签上遇到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
文件,然后导入fs
和crypto
模块:
import crypto from 'crypto';
import fs from 'fs';
我们需要fs
模块来读取要验证完整性的文件的内容。让我们声明资源名称和预期完整性:
const resource = 'jquery-3.6.4.min.js';
const expectedIntegrity = 'oP6HI9z1XaZNBrJURtCoUT5SUnxFr8s3BzRl+cbzUq8=';
请注意,sha256
在integrity
属性的值面前只是该哈希的名称,该哈希算法已计算出来,因此我们在比较时跳过它。
让我们阅读文件内容并使用sha256
算法计算摘要:
const jquerySource = fs.readFileSync(resource);
const digest = crypto
.createHash('sha256')
.update(jquerySource, 'utf8')
.digest();
const calculatedIntegrity = digest.toString('base64');
digest
变量的值是一种称为Buffer
的类型,它只是一个字节,因此我们需要将其转换为base64
编码中的字符串。
最后,我们只需要将calculatedIntegrity
与expectedIntegrity
进行比较,如果它们是相等的,那么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上写的代码的完整版本。