我一直在阅读MSDN,强名称程序集和相关的Stack Overflow问题中的正确文章,检查程序集的强名称.
在何种程度上可以验证强名称的装配以避免篡改?
是否可以使用强命名来验证程序集作者?
第一个问题出现在阅读CSharp411文章.NET程序集常见问题 - 第3部分 - 强名称和签名之后,其中提到了这一点,以及使用强名称的其他问题:
" 无法完全替换.强名称不能阻止黑客删除强名称签名,恶意修改程序集,用自己的密钥重新签名,然后将你的程序集作为你的程序. "
第二个问题旨在找出强命名和其他签名方案之间的差异,例如Authenticode.同样的MSDN文章提到了早期的状态:
"但请注意,强名称本身并不意味着一定程度的信任,例如通过数字签名和支持证书提供的信任. "
我是否尝试使用强命名,而不是创建它?创建强命名是为了避免名字冲突还是一种新的"GAC DLL Hell"?
根据您创建的私钥对具有强名称的程序集进行签名时,具有以下优点:
强名称通过向程序集添加公钥令牌和数字签名来保证程序集标识的唯一性.
可以将强名称与公钥匹配,以证明程序集来自具有该公钥的发布者,并且仅来自该发布者.
强名称提供强大的完整性检查.传递.NET Framework安全性检查可确保自上次构建程序集以来未更改程序集的内容.
是否可以使用强命名来验证程序集作者?
是的,如上所述,强命名可以验证程序集的最新作者.但它没有验证原作者.如果攻击者替换了程序集的强名称,那么所有可以验证的就是您不是程序集的最新作者.如果他删除了强名称,则根本无法进行作者验证.
在何种程度上可以验证强名称的装配以避免篡改?
以下C#代码验证攻击者是否在应用强名称时未篡改写入程序集的公钥令牌.它不会避免篡改,但它可以检测某些类型的篡改.下面的方法接受包含公钥标记的字节数组,并将其与程序集的实际标记进行比较.请注意,要使此技术有效,您选择的混淆器应该加密包含您的公钥令牌的字符串,并且只在使用时动态解密.并且还要注意,您需要具有FullTrust权限才能使此代码正常工作,因为它使用了底层的反射.
// Check that public key token matches what's expected. private static bool IsPublicTokenOkay_Check(byte [] tokenExpected) { // Retrieve token from current assembly byte [] tokenCurrent = Assembly.GetExecutingAssembly().GetName().GetPublicKeyToken(); // Check that lengths match if (tokenExpected.Length == tokenCurrent.Length) { // Check that token contents match for (int i = 0; i < tokenCurrent.Length; i++) if (tokenExpected[i] != tokenCurrent[i]) return false; } else { return false; } return true; }
只要您在.NET 3.5 SP1之前的.NET Framework版本下运行,您也可以强制验证强名称签名,以防攻击者删除强名称或禁用强名称检查.注册表中.下面的代码演示了对另一个名为NativeMethods的类的静态方法的调用.这是验证将被执行的地方.
// Check that this assembly has a strong name. private bool IsStrongNameValid_Check() { byte wasVerified = Convert.ToByte(false); byte forceVerification = Convert.ToByte(true); string assemblyName = AppDomain.CurrentDomain.BaseDirectory + AppDomain.CurrentDomain.FriendlyName; return NativeMethods.CheckSignature(assemblyName, forceVerification, ref wasVerified); }
实际签名验证使用P/Invoke完成,如下所示.StrongNameSignatureVerificationEx API 的使用非常复杂 - 要获得不错的解释,请参阅此博客条目.
// P/Invoke to check various security settings // Using byte for arguments rather than bool, // because bool won't work on 64-bit Windows! [DllImport("mscoree.dll", CharSet=CharSet.Unicode)] private static extern bool StrongNameSignatureVerificationEx(string wszFilePath, byte fForceVerification, ref byte pfWasVerified); // Private constructor because this type has no non-static members private NativeMethods() { } public static bool CheckSignature(string assemblyName, byte forceVerification, ref byte wasVerified) { return StrongNameSignatureVerificationEx(assemblyName, forceVerification, ref wasVerified ); }
请注意,对于使用.NET 3.5 SP1或更高版本的应用程序,默认情况下这不起作用,后者具有强名称绕过功能.这是可能的禁用此功能通过将设置其配置文件为您的应用程序.但是,任何具有对该配置文件的读/写访问权限的攻击者都可以改变您的决定.
Authenticode依赖第三方证书颁发机构进行证书验证.强命名的工作方式类似于自签名证书,可以这样处理.它确实使用标准的数字签名,但问题在于验证程序集作者的公钥确实有效.如果您通过作者的可信通道单独获取它并且您信任该通道,那么是的,您可以像自签名证书一样对其进行验证.
只要您确定强名称私钥由作者保密并且您知道作者的公钥,您就可以确保它没有被篡改(在某种程度上您可以确保数字签名的电子邮件不被篡改).顺便说一句,不要误解我的意思:引用完全正确,攻击者可以轻松地重新组装程序或删除现有的签名.但是,生成的程序集将具有**不同的*数字签名,可以根据原始签名进行检查(如果您有原始公钥).
在这种情况下,它类似于自签名证书.如果您能以某种方式确定作者的公钥,则可以验证权限.但是,与依赖于证书颁发机构的Authenticode不同,没有直接的,系统定义的方式来分发公钥.