如何防止.NET中的DLL欺骗

我有一个引用托管DLL的.NET应用程序。

这个DLL包含一个类,比如ScoreKeeper ,它实现了一个名为GetHighScore()的方法。 应用程序会定期调用它。

有没有办法阻止.NET应用程序使用“非授权”DLL代替我提供的DLL?

你提到:

这个DLL包含一个类,比如ScoreKeeper ,它实现了一个名为GetHighScore()的方法。 应用程序会定期调用它。

然后:

有没有办法阻止.NET应用程序使用“非授权”DLL代替我提供的DLL?

假设您想要阻止某人更换您自己的程序集,该程序集具有相同的名称和类型(在同一名称空间中),您可以 将强名称应用于包含ScoreKeeper 的程序集上课并让您的消费者参考。

但是,我们会发现有些问题使得这不是100%可靠。 强名称可帮助您保护不知情的用户免受恶意欺骗副本替换您的DLL。 但是如果用户是欺骗的同谋(如果他试图作弊就是这种情况),那么代码签名只不过是速度提升并且没有提供真正的保护。 当然,强名称不提供与PunkBuster相当的保护。

使用强名称validation程序集发布者的身份

向程序集添加强名称时,您正在使用私钥(非对称公钥/私钥对的一部分,稍后将详细介绍)生成加密哈希,并且公钥包含在程序集名称中(以及哈希)。

使用公共哈希和公钥,CLR能够validation程序集的签名实际上是否来自私钥。

当然,这意味着,你应该保护密钥(内部和外部); 如果其他人拥有你的密钥,那么他们就可以有效地冒充你并发布人们会信任你的程序集。

然后,当您添加对已签名程序集的引用时,如果有人尝试使用相同的程序集名称(不是完全限定的程序集,只是没有版本,哈希和公钥的名称)和相同的类型名称来放入不同的程序集,尝试加载类型时CLR填充失败,表示无法找到它; 使用完全限定的程序集名称以及名称空间和类型名称来解析类型。

为什么强名称不是100%安全(什么都有?)

1) 哈希碰撞

仍然是一个正在validation的哈希。 虽然散列非常大(默认散列算法为SHA-1的160位),但任何具有有限数量值的散列都会发生冲突。 虽然不可能,但可能(不可能与不可能)。 此外,默认情况下仅使用最后8个字节。 结合表明SHA-1相对较弱的研究,这是使用MSDN中描述的SHA-256增强型强命名的一个很好的理由。

2) 删除强名称

强名称可以删除。 但是,在这种情况下,因为您的程序集引用了引用程序集的强命名版本,所以当程序集尝试使用受损版本时,它将在运行时失败,假设您已正确重新启用validation(请参阅下文)。

3) 对组件的物理访问意味着所有组件

如果有人可以访问物理机并且可以修改您引用的程序集,那么您的程序集也同样容易受到攻击。 如果攻击者能够修改您引用的程序集的强名称,那么他们就可以轻松地修改程序集以及执行中涉及的所有其他程序 。 为此, 100%确定物理组件未被黑客攻击的唯一方法是拒绝通过它进行物理访问 。 当然,这带来了一系列不同的安全问题。

4) 管理员禁用强名称检查

计算机管理员可以使用sn -Vr简单地绕过强名称检查。 根据MSDN :

注册程序集以进行validation跳过…恶意程序集可以使用添加到跳过validation列表的程序集的完全指定的程序集名称(程序集名称,版本,区域性和公钥标记)来伪造其标识。 这将允许恶意程序集也跳过validation。

5) 必须在.NET 3.5 SP 1之后明确启用强名称检查

从.NET 3.5 SP 1开始, 只有一个强名称不提供任何保护 :

从.NET Framework 3.5版Service Pack 1(SP1)开始,当程序集加载到完全信任的AppDomain对象(例如MyComputer区域的默认AppDomain)时,不会validation强名称签名。

为了让.NET检查加载到应用程序中的每个程序集的强名称,您需要将以下代码段(由MSDN提供)插入到应用程序配置文件中:

      

但要注意,这只能防止删除强名称。

覆盖旁路function时,强名称仅在正确性方面有效; 不检查StrongNameIdentityPermission 。 如果要确认特定的强名称,则必须单独执行该检查。


如果考虑到上述问题,你仍然希望powershell命名你的assembly,这就是方法。

生成强名称并签署程序集

在生成强名称时,您有两个选项可供使用。 在Visual Studio中,转到项目属性上的“签名”选项卡,然后单击“签署程序集”:

在VS.NET中项目属性的“签名”选项卡上“签署程序集”选项

从那里,您有两个选项来生成公钥/私钥,让VS.NET为您生成密钥,或者指向现有密钥:

用于选择强名称密钥文件的“新建”或“浏览”选项

选择“新建”时,Visual Studio将提示您输入要生成的文件的名称,以及是否要选择使用密码来访问它:

创建强名称密钥对话框

此时,密钥将添加到您的项目中:

密钥添加到项目中

现在,您可以将其移动到解决方案项目(如果解决方案中有多个项目)。

在这种情况下,Visual Studio实际上只是调用Strong Name命令行工具来生成公钥和私钥对。 如果您更愿意自己这样做,则需要使用-k命令行选项调用sn.exe来生成密钥,如下所示:

 sn -k keyPair.snk 

然后通过上面的“浏览”对话框添加它。

请注意,执行此操作时,它会将密钥拉入项目中。 如果您不想这样做(因为它将密钥复制到每个项目中), 则从项目中删除密钥,然后将现有文件添加到项目中,但链接它 。 这将清除“选择强名称密钥文件”选项,但如果将其删除,您将看到链接密钥文件的完整路径。

似乎最简单的答案是计算您正在加载的DLL的安全哈希值,然后将其与您预先计算的黄金值进行比较。 当然,这仍然很容易被一个足够坚定的攻击者打破,但它会显着提高想要作弊的人的标准。