【问题标题】:Can strong naming an assembly be used to verify the assembly author?可以使用强命名程序集来验证程序集作者吗?
【发布时间】:2010-09-27 00:32:53
【问题描述】:

我一直在阅读 MSDN 中的正确文章,Strong-Named Assemblies 和相关的 Stack Overflow 问题,Checking an assembly for a strong name

  1. 可以在多大程度上验证强名称程序集以避免篡改?
  2. 是否可以使用强命名来验证程序集作者?

第一个问题出现在阅读 CSharp411 文章 .NET Assembly FAQ – Part 3 – Strong Names and Signing 后,其中提到了这一点,以及使用强名称的其他问题:

"无法停止完全替换。强名称无法阻止黑客删除强名称签名、恶意修改您的程序集、使用自己的密钥重新签名、然后把他的程序集当作你的。”

第二个问题旨在找出强命名和其他签名方案(例如Authenticode)之间的区别。同一篇 MSDN 文章提到了早期状态:

但是请注意,强名称本身并不意味着像数字签名和支持证书那样提供的信任级别。

我是否试图将强命名用于比创建它的目的更多的用途?创建强命名只是为了避免名称冲突还是一种新的“GAC DLL Hell”?

【问题讨论】:

    标签: .net security assemblies strongname


    【解决方案1】:

    如果您想对您的程序集进行完整性检查,您必须进行公钥令牌检查(参见上文“HTTP 410”的答案)并使用 StrongNameSignatureVerificationEx (https://docs.microsoft.com/de-de/dotnet/framework/unmanaged-api/strong-naming/strongnamesignatureverificationex-function) 进行检查。 StrongNameSignatureVerificationEx 的结果和输出参数 pfWasVerified 都必须为真。 只需对所有程序集使用一个签名密钥文件 (.snk)。

    最好是一个像 BabelFor.Net 这样的好的 .NET 程序集混淆器。其中许多都有内置的防篡改检查。

    干杯

    【讨论】:

      【解决方案2】:

      我相信有一种方法可以使用强名称来达到“信任”的目的。我了解 Microsoft 仅建议使用强名称以确保程序集内容未被修改,并建议使用“Authenticode”来获得信任。

      但是,如果加载器应用程序(加载这些程序集/程序的应用程序)维护它可以加载的“程序集”的加密列表;那不是解决“信任”问题吗?

      例如,包加载器可以使用公钥维护程序集名称,并通过完整的程序集名称加载程序集/程序?

      【讨论】:

        【解决方案3】:

        当您使用基于您创建的私钥的强名称对程序集进行签名时,这具有以下好处:

        • 强名称通过向程序集添加公钥令牌和数字签名来保证程序集身份的唯一性。
        • 可以将强名称与公钥匹配,以证明程序集来自具有该公钥的发布者,并且仅来自该发布者。
        • 强名称提供强完整性检查。通过 .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 的使用相当复杂 - 要获得适当的解释,请参阅 this blog entry

        // 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 或更高版本(具有 strong name bypass feature)的应用程序。通过在其配置文件中添加设置,可以为您的应用程序 disable this feature。但当然,任何对该配置文件具有读/写访问权限的攻击者都可以推翻您的决定。

        【讨论】:

        • 谢谢!很好的例子。此检查会忽略/绕过哪些类型的篡改?
        • 此代码不会检测到攻击者更改了您的公钥令牌副本以匹配他自己的公钥的情况。当然,它无法检测到代码本身被阻止运行的篡改。
        • @RoadWarrior:好东西。我将不得不再考虑一下。
        • 这需要 .NET 3.5。对于具有 .NET 4 和更新版本的 Windows 8 机器,如何调整此代码来验证强名称签名?
        • @Igor,我已经更新了我的答案来回答你的问题。
        【解决方案4】:

        Authenticode 依赖第三方证书颁发机构进行证书验证。强命名就像自签名证书一样工作,可以这样对待。它确实使用标准数字签名,但问题在于验证程序集作者的公钥确实有效。如果您通过作者的受信任渠道单独获得它并且您信任该渠道,那么可以,您可以像自签名证书一样验证它。

        只要您确定作者保存了强名称私钥的安全并且您知道作者的公钥,您就可以确保它没有被篡改(在某种程度上您可以确保数字签名的电子邮件没有被篡改和)。顺便说一句,不要误会我的意思:引用完全正确,攻击者可以轻松地退出程序集或删除现有签名。但是,生成的程序集将有一个**不同的*数字签名,可以对照原始签名(如果您拥有原始公钥)。

        在这种情况下,它类似于自签名证书。如果您能以某种方式确定作者的公钥,则可以验证权限。但是,与依赖证书颁发机构的 Authenticode 不同,没有直接的、系统定义的方式来分发公钥。

        【讨论】:

        • 但是检查公钥是否是你知道有效的那个的验证,必须手动进行。不是吗?
        • 是的,我们在理论上谈论这个事实。在实践中,不建议为这些目的使用强名称。毕竟这是一个强name,而不是强signature。但从理论上讲,完成我所说的事情是可能且非常安全的方式,就像 GPG 签名左右一样..
        【解决方案5】:

        我认为强名称对于版本控制很有用,可用于帮助设置代码访问安全性的信任级别编辑但您不能使用它们来验证程序集是否正确由受信任的人或特定作者撰写。参见@RoadWarrior 的评论和@RoadWarrior 对此问题的回答。

        强命名您的程序集并不能使其防篡改。
        编辑:参见@RoadWarrior 和@divo 的cmets。如果您的应用程序正在检查程序集作者的原始私钥并强制进行强名称验证,我的陈述是不正确的。但是,如果攻击者可以访问您的应用程序中的所有程序集和/或您正在使用 CLR 免费提供的开箱即用的强名称验证,那么我坚持我所说的。

        这个可以被a determined attacker颠覆。

        我前段时间读过a discussion 中关于强名称和安全性的文章,这使我相信对于我们生产的程序集,authenticode 可以更好地保证我们的客户程序集来自可信赖的来源。

        【讨论】:

        • > 强命名您的程序集并不能使其防篡改。 不同的 签名。用 .NET 编写的受信任的 MS-Office 插件依赖于这一事实,顺便说一句。
        • Hamish,您可以使用强名称来验证程序集是否由特定作者创建,因为虽然攻击者可以篡改程序集,但他不可能重新使用原始程序集的强名称。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-03-18
        • 1970-01-01
        • 2012-05-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多