我一直在阅读MSDN中的正确文章 Strong-Named Assemblies 以及相关的Stack Overflow问题 Checking an assembly for a strong name 。
第一个问题出现在阅读CSharp411文章 .NET Assembly FAQ – Part 3 – Strong Names and Signing 之后,其中提到了这一点,以及使用强名称的其他问题:
“ 无法停止完全替换。 强名称无法阻止黑客删除强名称签名,恶意修改程序集,重新签名自己的钥匙,然后把他的装配作为你的装配。“
第二个问题旨在找出强命名与其他签名方案之间的差异,比如Authenticode。同样的MSDN文章提到了早期的状态:
“但是,请注意,强名称本身并不意味着一定程度的信任,例如,通过数字签名和支持证书提供的信任。”
我是否尝试使用强命名比创建它更多?创建强名称是为了避免名称冲突还是一种新的“GAC DLL Hell”?
答案 0 :(得分:22)
根据您创建的私钥对具有强名称的程序集进行签名时,具有以下优点:
是否可以使用强命名来验证程序集作者?
是的,如上所述,强命名可以验证程序集的最新作者。但它没有验证原作者。如果攻击者替换了程序集的强名称,那么所有可以验证的就是您不是程序集的最新作者。如果他删除了强名称,则根本无法进行作者验证。
在何种程度上可以验证强名称的装配以避免篡改?
以下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为您的应用程序。但是,任何具有对该配置文件的读/写访问权限的攻击者都可以改变您的决定。
答案 1 :(得分:12)
Authenticode依赖第三方证书颁发机构进行证书验证。强命名的工作方式类似于自签名证书,可以这样处理。它确实使用标准的数字签名,但问题在于验证程序集作者的公钥确实有效。如果您通过作者的可信渠道单独获取并且您信任该频道,那么您可以像自签名证书一样验证它。
只要您确定强名称私钥由作者保密并且您知道作者的公钥,您就可以确保它没有被篡改(在某种程度上您可以确保数字签名的电子邮件不被篡改用)。顺便说一句,不要误解我的意思:引用完全正确,攻击者可以轻松地重新组装程序或删除现有的签名。但是,生成的程序集将具有**不同的*数字签名,可以根据原始签名进行检查(如果您有原始公钥)。
在这种情况下,它类似于自签名证书。如果您能以某种方式确定作者的公钥,则可以验证权限。但是,与依赖于证书颁发机构的Authenticode不同,没有直接的,系统定义的方式来分发公钥。
答案 2 :(得分:1)
我认为强名称对于版本控制非常有用,可用于帮助设置代码访问安全性编辑:的信任级别,但您无法使用它们来验证程序集是由受信任的人或特定作者撰写。请参阅@RoadWarrior的评论和@ RoadWarrior对此问题的回答。
强力命名装配体并不会使其防篡改 修改:查看@RoadWarrior和@divo的评论。如果您的应用程序正在检查程序集作者的原始私钥并强制进行强名称验证,那么我的声明是不正确的。但是,如果攻击者可以访问您应用程序中的所有程序集和/或您正在使用CLR免费提供的开箱即用的强名称验证,那么我就支持我所说的。
这可以被a determined attacker破坏。
前段时间我读过a discussion有关强名称和安全性的信息,这让我相信,对于我们生产的组件,authenticode对我们的客户来说是一个更好的保证,即组件来自可信赖的来源。
答案 3 :(得分:0)
我相信有一种方法可以使用强名来实现&#34; Trust&#34;。据我所知,Microsoft仅推荐使用强名称来确保程序集内容未被修改,并建议使用&#34; Authenticode&#34;信任。
但是如果加载器应用程序(加载这些程序集/程序的应用程序)维护一个加密列表&#34; Assemblies&#34;它可以加载;不会解决&#34;信任&#34;问题
例如,包加载程序可以使用公钥维护程序集名称,并通过完整程序集名称加载程序集/程序?
答案 4 :(得分:0)
如果要完整性检查程序集,则必须进行公钥令牌检查(请参见上面“ HTTP 410”的答案),并使用 StrongNameSignatureVerificationEx (https://docs.microsoft.com/de-de/dotnet/framework/unmanaged-api/strong-naming/strongnamesignatureverificationex-function )。 StrongNameSignatureVerificationEx 的结果和输出参数 pfWasVerified 都必须为真。 只需对所有程序集使用一个签名密钥文件(.snk)。
更好的是像BabelFor.Net这样的.NET程序集混淆器。其中许多具有内置的防篡改检查。
欢呼