我对 .NET 程序集的强密钥签名的工作方式感到相当困惑。我通过插入密码并生成 .pfx 文件来使用强名称对我的 .NET 程序集进行签名...
这应该如何保护我的dll?有人可以简单地向我解释一下吗?我是数字签名的新手,您必须退后一步才能让我理解这一点
我对 .NET 程序集的强密钥签名的工作方式感到相当困惑。我通过插入密码并生成 .pfx 文件来使用强名称对我的 .NET 程序集进行签名...
这应该如何保护我的dll?有人可以简单地向我解释一下吗?我是数字签名的新手,您必须退后一步才能让我理解这一点
我是数字签名的新手,您必须退后一步才能让我理解这一点
好的,让我们退后一步,然后问一些更基本的问题。我会将每个具有精确含义的单词加粗。
安全系统的目的是什么?
保护资源(一堆金币)免受试图利用漏洞(未锁定的窗口)的敌对方(小偷)的成功攻击(盗窃)的威胁。(*)
.NET 的代码访问安全一般是如何工作的?
这是 .NET 1.0 安全系统的草图;它相当复杂,已或多或少被一个更简单的系统所取代,但基本功能是相同的。
每个程序集都向运行时提供证据。域管理员、机器管理员、用户和 appdomain 创建者每个都可以创建安全策略。策略是在存在特定证据时授予哪些权限的声明。当一个程序集试图执行一个潜在的危险操作时——也就是说,一个可能对资源构成威胁的操作——运行时要求授予权限。如果证据不足以授予该权限,则操作失败并出现异常。
例如,假设一个程序集显示“我刚刚从 Internet 下载”的证据,并且策略说“从 Internet 下载的代码获得运行和访问打印机的权限”,然后该代码尝试写入C:\Windows\System32
. 因证据不足未授予权限,操作失败。资源——系统目录的内容——被保护不被篡改。
使用从 VeriSign 获得的数字证书对程序集进行签名的目的是什么?
使用数字证书签名的程序集向运行时提供描述用于签署程序集的证书的证据。管理员、用户或应用程序可以修改安全策略以声明该证据可以授予特定权限。
使用数字证书签名的程序集提供的证据是:该程序集由拥有与该证书关联的私钥的人签名,并且证书持有者的身份已通过 VeriSign 验证。
数字证书使您的软件用户能够根据您的身份由受信任的第三方验证来做出信任决定。
那么这如何保护我的 DLL 呢?
它没有。您的 DLL 是用来撬开窗户的撬棍,而不是一堆金币!您的 DLL 首先不是要保护的资源。用户的数据是要保护的资源。数字签名的存在是为了促进现有的信任关系。您的客户信任您编写的代码符合标签上的要求。签名使他们能够知道他们正在运行的代码确实来自您,因为代码作者的身份已由受信任的第三方验证。
那么强命名不是同样的事情吗?
不。
强命名是相似的,因为强命名 DLL 向运行时提供了强大的加密证据,表明程序集是由与特定公钥关联的特定私钥签名的。但是强命名的目的是不同的。正如该术语所暗示的,强命名是为只能与真实程序集关联的程序集创建名称。任何人都可以创建一个名为 foo.dll 的 DLL,如果您通过其弱名称将 foo.dll 加载到内存中,您将获得该名称机器上的任何 DLL,无论是谁创建的。但是只有公钥对应的私钥的拥有者才能制作一个强名称的dll foo, Version=1.2.3.4, Culture=en, PublicKeyToken=03689116d3a4ae33
。
同样,强命名的目的并不是直接促进软件提供者和用户之间的信任关系。强命名的目的是确保使用您的库的开发人员真正使用的是您实际发布的该库的特定版本。
我注意到 VeriSign 不是强命名的一个因素。没有可信的第三方吗?
这是正确的; 对于强名称,没有可信的第三方来验证与给定强名称相关联的公钥是否实际上与特定组织或个人相关联。
数字证书中的这种机制促进了信任关系,因为受信任的第三方可以保证公钥确实与受信任的组织相关联。由于缺乏这种机制,强名称的消费者需要知道您组织的公钥是什么。如何安全地与他们沟通取决于您。
强命名时没有受信任的第三方这一事实是否还有其他含义?
是的。例如,假设有人闯入您的办公室并窃取了带有数字证书私钥的计算机。该攻击者现在可以生成使用该密钥签名的软件。但是 VeriSign 等认证机构会发布已知被泄露证书的“撤销列表”。如果您的客户从他们的认证机构下载吊销列表是最新的,那么一旦您吊销您的证书,他们就可以检测到您的软件可能来自敌对的第三方。然后,您将面临获取新证书、重新签署所有代码并将其分发给客户的艰巨任务,但至少有一些机制可以处理这种情况。
强名称则不然。没有中央认证机构可以要求获得一份受损的强名称列表。如果您的强名称私钥被盗,那么您就不走运了。没有撤销机制。
我查看了我的默认安全策略,它说 (1) 本地计算机上的任何代码都是完全可信的,并且 (2) 本地计算机上由 Microsoft 强命名的任何代码都是完全可信的。这不是多余的吗?
是的。这样,如果第一个策略的限制性更强,那么第二个策略仍然适用。管理员可能希望降低已安装软件的信任级别而不降低必须完全信任的程序集的信任级别似乎是合理的,因为它们保持安全系统本身工作。
但是等一下,这似乎仍然是多余的。为什么不将默认策略设置为“(1) 本地计算机上的任何代码都是受信任的 (2) Microsoft 强命名的任何代码都是完全受信任的”?
假设发生灾难并且 Microsoft 私钥被泄露。它被深深地存放在 11 号楼下的一个保险库中,受到鲨鱼的激光束保护,但仍然假设发生了这种情况。这将是一场史诗般的灾难,因为就像我刚才所说的那样,没有撤销系统。如果发生这种情况并且安全策略如您所描述,那么拥有密钥的攻击者可以将恶意软件放在互联网上,然后由默认安全策略完全信任!根据实际规定的安全策略——需要强名称和本地机器位置——拥有私钥的攻击者现在必须欺骗用户下载和安装它。
这是“纵深防御”的一个例子。始终假设所有其他安全系统都失败了,并且仍然尽最大努力阻止攻击者。
作为最佳实践,您应始终设置强名称或数字签名策略以包含位置。
再说一遍,强命名并不是为了保护我的 DLL。
正确的。安全系统的目的绝不是保护您、软件供应商或您生产的任何工件。这是为了保护您的客户免受试图利用您与您之间的信任关系的攻击者的攻击。强名称可确保使用您的库的代码确实在使用您的库。它通过创建一个非常方便的机制来识别特定 DLL 的特定版本来做到这一点。
我在哪里可以阅读更多内容?
我已经写了一本关于 .NET 1.0 安全系统的短书,但它现在已经绝版,并且无论如何都被新的简化系统所取代。
以下是我写的关于这个主题的更多文章:
http://ericlippert.com/2009/06/04/alas-smith-and-jones/
(*) 安全系统除了防止攻击成功之外还有其他目标;一个好的安全系统还将提供攻击成功的不可否认的证据,以便攻击者可以在攻击后被追踪和起诉。这些特性超出了本次讨论的范围。
简而言之,主要目的之一是防止 CLR 在更改后加载程序集。例如,你发布了一个带有 DLL 的软件,有人可以反映它,更改代码,然后重新构建它,然后让你的程序加载它,认为它是你的 dll。为了防止这种情况,当您构建 dll 并与它一起存储时,会计算一个哈希值。在运行时,当 CLR 加载 DLL 时,它会再次计算哈希值并与存储在 DLL 中的内容进行比较,如果 DLL 仍然完好无损,那么它应该匹配并且 CLR 会加载它,否则它不会加载。
这应该会给你一个很好的解释,包括更多细节:
http://resources.infosecinstitute.com/dot-net-assemblies-and-strong-name-signature/