22

我一直在阅读 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”?

4

5 回答 5

23

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

  • 强名称通过向程序集添加公钥令牌和数字签名来保证程序集身份的唯一性。
  • 强名称可以与公钥匹配,以证明程序集来自具有该公钥的发布者,并且仅来自该发布者。
  • 强名称提供强完整性检查。通过 .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 或更高版本(具有强名称绕过功能)的应用程序。可以通过将设置添加到其配置文件来为您的应用程序禁用此功能。但是当然,任何对该配置文件具有读/写访问权限的攻击者都可以推翻您的决定。

于 2008-12-15T19:40:04.190 回答
12

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

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

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

于 2008-12-15T18:27:17.020 回答
1

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

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

这可以被一个坚定的攻击者颠覆。

前段时间我读过一篇关于强名称和安全性的讨论,这让我相信对于我们生产的程序集,authenticode 可以更好地保证我们的客户程序集来自受信任的来源。

于 2008-12-15T18:40:32.797 回答
0

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

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

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

于 2016-07-22T18:27:05.973 回答
0

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

更好的是像 BabelFor.Net 这样的好的 .NET 程序集混淆器。其中许多具有内置的防篡改检查功能。

干杯

于 2020-10-22T03:02:47.980 回答