Subresource Integrity (SRI) 在保护第三方脚本完整性方面的局限性是什么？如何绕过它？

admin
Wed, 23 Jul 2025 09:36:27 +0000
Javascript, integrity, sri, subresource

各位观众，晚上好！欢迎来到今天的“前端安全大作战”特别节目。我是你们的老朋友，bug终结者，今天咱们聊聊Subresource Integrity (SRI) 这玩意儿，看看它是不是真的那么靠谱，以及有哪些“不听话”的地方，还有那些“心怀不轨”的家伙是怎么绕过它的。 开场白：SRI，你的盾牌够硬吗？ 话说江湖上流传着一种叫做SRI的“神功”，据说能保护咱们的前端代码不被第三方CDN的坏人篡改。听起来是不是很厉害？就像给你的网页穿上了一层金钟罩铁布衫，刀枪不入。 但，等等！武侠小说里都说了，没有绝对的防御。再厉害的盾牌，也总有弱点。今天咱们就来扒一扒SRI的底裤，看看它到底有哪些局限性，又有哪些方法能绕过它，当然，我们学习这些是为了更好地保护我们的代码，而不是去干坏事啊！ 第一幕：SRI的基本原理，知己知彼 要想知道SRI的局限性，咱们得先了解它是个什么玩意儿。简单来说，SRI就是给你的外部资源（比如CDN上的JavaScript、CSS文件）生成一个唯一的“指纹”——哈希值。当浏览器加载这些资源的时候，会拿下载下来的文件的哈希值和你事先提供的哈希值进行比对。如果不一样，那就说明这个文件 …

继续阅读“Subresource Integrity (SRI) 在保护第三方脚本完整性方面的局限性是什么？如何绕过它？”

The post Subresource Integrity (SRI) 在保护第三方脚本完整性方面的局限性是什么？如何绕过它？ first appeared on 智猿学院-前后端，数据库，人工智能，云计算等领域前沿技术讲座.

各位观众，晚上好！欢迎来到今天的“前端安全大作战”特别节目。我是你们的老朋友，bug终结者，今天咱们聊聊Subresource Integrity (SRI) 这玩意儿，看看它是不是真的那么靠谱，以及有哪些“不听话”的地方，还有那些“心怀不轨”的家伙是怎么绕过它的。

开场白：SRI，你的盾牌够硬吗？

话说江湖上流传着一种叫做SRI的“神功”，据说能保护咱们的前端代码不被第三方CDN的坏人篡改。听起来是不是很厉害？就像给你的网页穿上了一层金钟罩铁布衫，刀枪不入。

但，等等！武侠小说里都说了，没有绝对的防御。再厉害的盾牌，也总有弱点。今天咱们就来扒一扒SRI的底裤，看看它到底有哪些局限性，又有哪些方法能绕过它，当然，我们学习这些是为了更好地保护我们的代码，而不是去干坏事啊！

第一幕：SRI的基本原理，知己知彼

要想知道SRI的局限性，咱们得先了解它是个什么玩意儿。简单来说，SRI就是给你的外部资源（比如CDN上的JavaScript、CSS文件）生成一个唯一的“指纹”——哈希值。当浏览器加载这些资源的时候，会拿下载下来的文件的哈希值和你事先提供的哈希值进行比对。如果不一样，那就说明这个文件被篡改了，浏览器会拒绝执行，防止恶意代码入侵。

举个例子，你在HTML里这样写：

<script
  src="https://cdn.example.com/jquery.min.js"
  integrity="sha384-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
crossorigin="anonymous">

这里的integrity属性就是SRI的关键。sha384-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 是jquery.min.js的哈希值。 crossorigin="anonymous"是为了处理跨域资源请求的，后面会提到。

第二幕：SRI的局限性，漏洞百出

好，现在我们知道了SRI的基本原理，接下来就要开始“找茬”了。SRI虽然能提供一定程度的保护，但它并不是万能的，存在不少局限性：

1. 只能保护静态资源： SRI只能验证静态文件的完整性，比如JavaScript、CSS文件。对于动态生成的内容，或者服务端返回的数据，SRI就无能为力了。

想象一下，你的页面通过AJAX从服务器获取数据，然后动态渲染到页面上。如果服务器被攻破，返回了恶意数据，SRI是拦不住的。

2. 依赖于可信的哈希值： SRI的安全性完全依赖于你提供的哈希值是否正确、可信。如果你不小心使用了被篡改的文件的哈希值，或者哈希值被中间人攻击替换了，那SRI就形同虚设了。

这就好比你用一把错误的钥匙去开门，门肯定会被坏人打开。

3. 无法防止DDoS攻击： SRI无法防止CDN被DDoS攻击，导致资源无法加载。虽然SRI能保证资源完整性，但如果资源根本无法获取，你的网页还是会崩溃。

4. 对动态内容无能为力: 假设CDN服务器的响应头允许动态生成内容（例如，基于用户代理或时间），那么SRI就无法保证资源的完整性，因为它只能验证静态内容。

5. 哈希算法选择的限制: 虽然现代浏览器支持多种哈希算法（如SHA-256、SHA-384、SHA-512），但如果浏览器不支持你选择的哈希算法，SRI验证将会失败。

6. 开发和维护成本: 每次CDN上的资源更新后，你都需要重新生成哈希值，并更新HTML中的integrity属性。这增加了一定的开发和维护成本。

7. 错误处理不友好: 当SRI验证失败时，浏览器只会简单地阻止资源加载，并不会提供详细的错误信息，这给调试带来了一定的困难。

8. Subresource Integrity 不防范供应链攻击：
SRI 主要目的是验证从 CDN 下载的文件的完整性，防止文件在传输过程中被篡改。如果 CDN 上的原始文件已经被攻击者篡改（例如，攻击者入侵了 CDN 供应商的服务器），SRI 就无法提供保护，因为它验证的是已经被篡改的文件的哈希值。

这种攻击被称为供应链攻击，因为攻击发生在软件供应链的上游。攻击者通过控制软件的构建、发布或分发过程，将恶意代码注入到软件中，从而影响所有使用该软件的用户。

SRI 无法防范供应链攻击的原因：

SRI 验证的是文件的哈希值，而不是文件的来源。 只要攻击者能够篡改 CDN 上的原始文件，并更新相应的哈希值，SRI 就会认为文件是完整的。

SRI 无法验证 CDN 供应商的安全性。 SRI 假设 CDN 供应商是可信的，但如果 CDN 供应商本身被攻击，SRI 就无法提供保护。

9. 浏览器兼容性问题:
虽然现代浏览器普遍支持 SRI，但仍然存在一些老旧浏览器不支持 SRI。在使用 SRI 时，需要考虑浏览器兼容性，并提供适当的降级方案，以确保在不支持 SRI 的浏览器上也能正常加载资源。

第三幕：绕过SRI的奇技淫巧，防不胜防

既然SRI有这么多局限性，那么“坏人”有没有办法绕过它呢？答案是肯定的。以下是一些常见的绕过SRI的方法：

1. 中间人攻击（MITM）： 如果攻击者能够控制你的网络，他就可以通过中间人攻击篡改你的HTML页面，替换掉integrity属性的值，或者直接删除integrity属性。这样，浏览器就不会进行SRI验证，恶意代码就可以畅通无阻地执行了。

这就好比坏人偷偷换掉了你的门锁，然后用自己的钥匙打开了你的家门。

2. 利用旧版本漏洞： 某些旧版本的浏览器可能存在SRI的实现漏洞，攻击者可以利用这些漏洞绕过SRI验证。

这就好比你的金钟罩铁布衫有个地方破了个洞，坏人可以从这个洞里钻进去。

3. 服务器端注入: 如果攻击者能够控制服务器，他们可以直接修改服务器返回的HTML响应，删除或修改integrity属性。

4. 依赖项混淆攻击: 攻击者可能会通过在你的项目依赖中引入恶意软件包，这些软件包可能会绕过或禁用 SRI 检查。

5. 利用其他漏洞： 如果你的网站存在其他的安全漏洞，比如XSS漏洞，攻击者可以通过XSS漏洞注入恶意代码，绕过SRI的保护。

这就好比你的房子除了门之外还有窗户，坏人可以从窗户爬进去。

6. 篡改DNS解析： 通过篡改DNS解析，将CDN域名指向攻击者控制的服务器。攻击者可以在自己的服务器上提供与CDN相同的资源，但包含了恶意代码。由于浏览器从攻击者控制的服务器下载资源，SRI验证实际上是在验证恶意代码的哈希值。

代码演示：中间人攻击绕过SRI

为了更直观地说明中间人攻击是如何绕过SRI的，我们可以使用一个简单的工具来模拟中间人攻击。比如，我们可以使用mitmproxy这个工具。

首先，我们需要安装mitmproxy：

pip install mitmproxy

然后，启动mitmproxy：

mitmproxy

接下来，我们需要配置我们的浏览器，让它通过mitmproxy代理所有的HTTP/HTTPS流量。具体的配置方法可以参考mitmproxy的官方文档。

现在，我们可以编写一个简单的mitmproxy脚本，用于篡改HTML页面，删除integrity属性：

from mitmproxy import http

def response(flow: http.HTTPFlow):
    if flow.request.url.endswith(".html"):
        flow.response.text = flow.response.text.replace('integrity="sha384-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"', '')

将这个脚本保存为remove_sri.py，然后使用以下命令启动mitmproxy：

mitmproxy -s remove_sri.py

现在，当我们访问包含SRI的HTML页面时，mitmproxy会自动删除integrity属性，从而绕过SRI验证。

表格总结：SRI的优缺点

为了更清晰地了解SRI的优缺点，我们可以用一张表格来总结：

特性 | 优点 | 缺点
完整性验证 | 确保从CDN加载的资源未被篡改，防止恶意代码注入。 | 无法保护动态生成的内容，依赖于可信的哈希值，无法防止DDoS攻击，对供应链攻击无效。
安全性 | 提高前端安全性，降低被XSS攻击的风险。 | 容易被中间人攻击绕过，可能存在浏览器兼容性问题，错误处理不友好，需要定期更新哈希值。
性能 | 可以利用浏览器缓存，提高页面加载速度。 | 每次资源更新都需要重新生成哈希值，增加了开发和维护成本。
易用性 | 使用简单，只需要在HTML中添加integrity属性即可。 | 需要手动生成和更新哈希值，容易出错。
保护范围 | 主要保护静态资源（JavaScript、CSS文件）。 | 对动态内容、服务端返回的数据、以及CDN本身的安全问题无能为力。

第四幕：如何正确使用SRI，扬长避短

既然SRI有这么多局限性，那我们是不是就不用它了呢？当然不是！SRI仍然是一种有效的安全措施，可以提高前端安全性。关键在于我们要正确使用它，扬长避短。

以下是一些使用SRI的最佳实践：

1. 使用HTTPS： 确保你的网站使用HTTPS协议，防止中间人攻击。

2. 使用可信的CDN： 选择信誉良好的CDN服务提供商，降低CDN被攻破的风险。

3. 定期更新哈希值： 每次CDN上的资源更新后，都要重新生成哈希值，并更新HTML中的integrity属性。

4. 使用多种哈希算法： 为了提高兼容性，可以使用多种哈希算法，比如SHA-256、SHA-384、SHA-512。

5. 配置CSP： 使用Content Security Policy (CSP) 限制可以加载的资源来源，进一步提高安全性。

6. 监控SRI错误： 监控浏览器的SRI错误报告，及时发现和解决问题。

7. 结合其他安全措施： 不要把SRI当成唯一的安全措施，要结合其他的安全措施，比如XSS防御、CSRF防御等，构建一个完整的安全体系。

代码示例：使用多种哈希算法

为了提高兼容性，我们可以在integrity属性中使用多种哈希算法：

<script
  src="https://cdn.example.com/jquery.min.js"
  integrity="sha256-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx sha384-yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy sha512-zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz"
crossorigin="anonymous">

浏览器会选择它支持的第一个哈希算法进行验证。

第五幕：展望未来，SRI的进化之路

SRI虽然存在一些局限性，但它仍然在不断进化。未来，我们可以期待SRI在以下方面有所改进：

1. 支持动态内容： 探索如何对动态生成的内容进行完整性验证。

2. 自动化哈希值更新： 自动化哈希值生成和更新的过程，降低开发和维护成本。

3. 更友好的错误处理： 提供更详细的SRI错误信息，方便调试。

4. 更强的安全性： 研究更安全的哈希算法，防止中间人攻击。

5. 与供应链安全结合： 将SRI与供应链安全措施结合起来，防止供应链攻击。

总结陈词：SRI，任重道远

总而言之，SRI是一种有用的安全措施，但它并不是万能的。我们需要了解它的局限性，正确使用它，并结合其他的安全措施，才能构建一个更安全的前端应用。

记住，安全是一个持续的过程，没有一劳永逸的解决方案。我们需要不断学习，不断进步，才能应对日益复杂的安全威胁。

今天的“前端安全大作战”就到这里，感谢大家的收看！我们下期再见！