如何防止.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为您生成密钥,或者指向现有密钥:
选择“新建”时,Visual Studio将提示您输入要生成的文件的名称,以及是否要选择使用密码来访问它:
此时,密钥将添加到您的项目中:
现在,您可以将其移动到解决方案项目(如果解决方案中有多个项目)。
在这种情况下,Visual Studio实际上只是调用Strong Name命令行工具来生成公钥和私钥对。 如果您更愿意自己这样做,则需要使用-k
命令行选项调用sn.exe
来生成密钥,如下所示:
sn -k keyPair.snk
然后通过上面的“浏览”对话框添加它。
请注意,执行此操作时,它会将密钥拉入项目中。 如果您不想这样做(因为它将密钥复制到每个项目中), 则从项目中删除密钥,然后将现有文件添加到项目中,但链接它 。 这将清除“选择强名称密钥文件”选项,但如果将其删除,您将看到链接密钥文件的完整路径。
似乎最简单的答案是计算您正在加载的DLL的安全哈希值,然后将其与您预先计算的黄金值进行比较。 当然,这仍然很容易被一个足够坚定的攻击者打破,但它会显着提高想要作弊的人的标准。