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

各位观众,晚上好!欢迎来到今天的“前端安全大作战”特别节目。我是你们的老朋友,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"></script>

这里的integrity属性就是SRI的关键。sha384-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxjquery.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"></script>

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

第五幕:展望未来,SRI的进化之路

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

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

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

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

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

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

总结陈词:SRI,任重道远

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

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

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

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注