我一直理解签署程序集的目的是进行运行时检查,以确保对代码的升级来自受信任的来源。实际上,他们正试图避免这种情况:
我从 A 公司购买了一个加密库,不久之后,B 公司获得了我的电子邮件详细信息,并向我发送了一个免费升级到该程序集,假装是 A 公司的一个重大安全漏洞修复程序,实际上它确实注入了一个隐藏的方法我的代码将我试图加密的所有数据发送到 B 公司的服务器。假设我是个白痴,并且盲目地将这个新的 dll 添加到我的应用程序的 bin 目录中,那么它没有使用与旧版本相同的私钥签名这一事实将在运行时被拾取,从而导致异常并保护我的数据。
因此,我认为您没有理由在程序集之外发布公钥,因为它不应该保证原始文件来自特定供应商,只是所有后续版本都来自与首先。
Wikipedia 说了很多相同的话(只是用词少得多)。
已编辑以添加更多信息以使这一点更清晰...
我认为首先需要澄清的是公钥和私钥对是唯一的。这意味着知道公钥并不足以重建程序集以使其通过相同的哈希检查。
所以用户 Z 正在使用来自公司 A 的加密库,该库位于他的应用程序 bin 文件夹中。为此,他按如下方式引用 DLL:
Encryption, Version=1.0.0.0, Culture=neutral, PublicKeyToken=bcd6707151635d07"
公钥的目的是为我们提供three benefits,我将一次处理一个。
首先,它为程序集提供了一个唯一的名称——这没有给我们额外的安全性,但确实阻止了 C 风格的 dll 地狱,两个不同的公司可以发布两个不同的库,称为 Encyption 版本 1.0.0.0,而你将无法将它们存储在同一目录中,因为无法区分它们。
其次,它阻止了我在原始帖子中概述的情况。 B 公司不可能创建另一个版本的加密库,它也是 1.0.0.0 版本并具有相同的公钥(这样整个名称就会匹配,并且您会调用他们的代码而不是 A 公司的代码)。他们不能这样做,因为如果他们的公钥匹配,那么私钥也必须匹配(因为每个 pair 都是唯一的)。他们可以让私钥匹配的唯一方法是破坏 A 公司的安全性。
最后,它确保了文件的完整性(通过损坏或恶意代码注入进行更改)。 dll 在运行时(当它是私有的并且在应用程序的 bin 文件夹中时)或安装时(当您将它放在 GAC 中时)使用公钥进行哈希处理,并将该哈希值与私有加密的哈希值进行比较密钥并存储在程序集中。 This page 有一些图表和更多细节。再一次,伪造此哈希的唯一方法是知道私钥。
因此,为了涵盖我上面描述的特定场景,假设我是 B 公司,试图向用户 Z 提供加密 dll 的恶意版本。我的第一次尝试是简单地使用名称加密和版本 1.0.0.0 制作我自己的 dll,并使用我自己的密钥对对其进行签名。不幸的是,我无法更改用户 Z 应用程序中的参考代码,因此它无法通过全名检查并且不会被加载。 “好吧,”我一边捻着小胡子一边说,“我将简单地更改我的程序集的公钥以匹配 A 公司的公钥。”完成此操作后,名称检查通过,但哈希检查将失败,因为用户 Z 的应用程序将无法使用公钥(公司A's) 已提供。因此,B 公司创建伪装成 A 公司的库的唯一方法是知道 A 公司的私钥。除了在程序集的原始版本中,这些安全检查都不依赖于 A 公司在其他任何地方发布公钥。
另请注意,所有这些功能都不能确保(也不声称确保)原始程序集来自 A 公司,由其他系统处理,例如 Verisign 或 Microsoft 的 Authenticode 服务,他们只确保一旦您引用了程序集,只有 A 公司可以更改该代码。