我该如何确保通过CDN传递的JavaScript文件不被篡改?

94

我正在处理一个情境,其中一些JavaScript文件将托管在CDN上。我想要某种机制,以便在用户下载这些文件时,我可以确保文件没有被篡改,并且确实来自指定的CDN。

我知道如果我使用SSL,任务会非常容易,但是即使在没有SSL的HTTP下,我也希望确保正确的文件被提供。

据我所搜寻,似乎没有现有的数字签名机制用于JavaScript文件并跨平台支持。也许不需要?

浏览器内置了一些方法来验证JavaScript文件的作者吗?是否有任何安全的方法可以实现此目的?


13
我觉得这个问题很有意思,但它不是主题吗? - evolutionxbox
21
为什么要在HTTP上提供文件? - njzk2
12
“但为什么没有这样的机制呢?”因为这非常困难。一旦您的数据离开服务器,它就无法控制。HTTPS 有所帮助,但如果是普通的HTTP连接,则任何验证都可能失败(或者更准确地说- 通过)。中间人攻击可以修改您期望的签名和/或提供给您的内容的签名,然后再将其发送到浏览器在处理期望结果之前。因此,当用户接收到某些负载时,即使负载并不完全安全,也会被视为完全安全。 - VLAZ
5
“为什么没有这样的机制?” 因为 HTTPS 已经提供了一种廉价、有效且广泛适用的解决方案。 - Kevin Krumwiede
10
这个内容最好放在ServerFault或Security上,因为它实际上是关于以安全的方式提供文件的,与编程的关系仅仅是因为这些文件恰好代表源代码而已。 - underscore_d
显示剩余17条评论
6个回答

141
事实上,像这样的功能正在以“子资源完整性(Subresource Integrity)”的名称撰写的草案中。请查看

10
值得一提的是,如果OP计划通过HTTP发送他们的HTML文件以及资源文件,完整性检查很容易被欺骗。如果他们的网站是HTTPS并且想要通过HTTP提供资源,则大多数浏览器将不会喜欢这种情况,并会静默忽略HTTP资源。 - MonkeyZeus
3
只有在中间人攻击或我们自己的服务器被入侵的情况下,这种说法才是正确的,对吗?我的理解是问题明确要求如何防御受到入侵的 CDN。 - TimoStaudinger
10
没错!如果没有这些检查机制,假如你从https://code.jquery.com/引用了一个脚本,那么任何篡改了code.jquery.com的人都能够对你的网站进行跨站脚本攻击,无论是否使用HTTPS访问code.jquery.com。但是有了这些检查机制,攻击者只能防止脚本加载,而不能替换为恶意脚本。 - Ajedi32
1
@MonkeyZeus 我在我的答案中添加了一条注释,说明了你的担忧。你同意这个措辞吗? - TimoStaudinger
1
@TimoSta 很好,我喜欢它!顺便说一下,在我发表第一条评论之前,我就已经点赞了 +1 :-) - MonkeyZeus
显示剩余6条评论

36
您正在寻找子资源完整性检查。
例如,这是jQuery CDN代码片段:
<script src="https://code.jquery.com/jquery-3.1.0.js"
        integrity="sha256-slogkvB1K3VOkzAI8QITxV3VzpOnkeNVsKvtkYLMjfk="
        crossorigin="anonymous"></script>

2
完全没有用,因为攻击者可以在下载脚本的同时修改完整性字段。 - Lightness Races in Orbit
15
如果您控制自己的域并通过HTTPS访问,但无法控制code.jquery.com,那么这可以保护您免受遭到攻击的code.jquery.com的影响。 - SilverlightFox
2
@SilverlightFox:好的,对抗中间人攻击*完全无用。 - Lightness Races in Orbit
@LightnessRacesinOrbit 是的。仍然非常有用,例如可以防止这种攻击:https://www.bleepingcomputer.com/news/security/twilio-exposes-sdk-attackers-inject-it-with-malvertising-code/ - Adrian Mouat

6
免责声明: 如往常一样,在使用https时,您应该仅考虑这些机制是有用的,因为它们可以通过http的MitM轻松禁用。
除了上面的解答中的机制外,您还可以在父页面上使用内容安全策略(content-security policy)http响应头。

http://www.html5rocks.com/en/tutorials/security/content-security-policy/

内容安全策略:script-src 'sha256-qznLcsROx4GACP2dm0UCKCzCG-HiZ1guq6ZZDob_Tng='

需要注意几点。sha*-前缀指定用于生成哈希值的算法。在上面的示例中,使用了sha256-。CSP还支持sha384-和sha512-。生成哈希时不要包括标签。此外,大小写和空格也很重要,包括前导或尾随空格。

使用Chrome 40或更高版本,您可以打开DevTools,然后重新加载页面。控制台选项卡将包含每个内联脚本的正确sha256哈希的错误消息。

这种机制已经存在了相当长的时间,因此浏览器支持可能非常好,只需确保检查即可。

此外,如果您想确保旧的不符合规范的浏览器不会不安全,您可以在页面顶部包含一个同步重定向脚本,该脚本不被策略允许。


Subresource Integrity 已经存在了一段时间,但浏览器支持并不是很好。http://caniuse.com/subresource-integrity - Sp0T
@Sp0t - 子资源完整性(你链接所涉及的内容)是其他答案中的机制。我的答案是关于内容安全策略,它有更好的支持。 - Fabio Beltramini

3

关于此类签名可以做什么和不能做什么,有一个重要的要点。它可以保护用户免受某人修改您的代码的假想攻击。它无法确保您的站点正在执行的是您的代码。换句话说,您仍然不能信任从客户端发送到您的站点的任何内容。


2
如果您的对手模型允许攻击者在从CDN传递JavaScript文件时进行修改,则您的对手模型允许攻击者修改引用源以删除任何验证尝试,更改源地址以及/或完全删除对JavaScript的引用。
而且,我们不要打开如何确定用户解析器是否通过HTTP请求(或任何其他没有经过验证的信任链机制)正确解析到CDN的潘多拉魔盒。
/etc/hosts:
#  ...
1.2.3.4    vile-pirates.org    trustworthy.cdn
#  ...

2
第一句话显然是不正确的。如果引用页面通过HTTPS加载,而JavaScript文件是通过HTTP-not-S加载的呢? - user253751
如果CDN被攻击,但是你自己的服务器没有被攻击呢? - Ajedi32
@immibis:我选择假设楼主不会如此不理性地提出这样的情况。 - Eric Towers
1
@immibis 这不就是为什么浏览器通常不允许HTTPS页面通过HTTP加载JS的原因吗? - Barmar
1
@immibis 我是在说它改善了一个根本不可能的情况,因为浏览器不允许它。 - Barmar
显示剩余3条评论

2
您可以通过子资源完整性来确保这一点。许多公共CDN在其网站上提供可嵌入代码时都包括SRI哈希。例如,在PageCDN上,当您单击jQuery CDN页面上的jquery文件时,您可以选择要么复制URL,要么使用包含SRI哈希的脚本标签,如下所示:
<script src="https://pagecdn.io/lib/jquery/3.4.1/jquery.min.js" integrity="sha256-CSXorXvZcTkaix6Yvo6HppcZGetbYMGWSFlBw8HfCJo=" crossorigin="anonymous"></script>

当页面加载时,浏览器会请求该资源,并在完成请求后将接收到的文件哈希值与在脚本标记中给出的完整性值进行匹配。如果两个哈希值不匹配,则浏览器将放弃该jQuery文件。
目前,全球91%的浏览器支持此功能。更多细节请参见caniuse

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接