当您使用基于私钥创建的强名称对程序集进行签名时,会有以下好处:
- 强名称通过向程序集添加公钥令牌和数字签名来保证程序集标识的唯一性。
- 可以将强名称与公钥匹配以证明该程序集来自具有该公钥的发布者且仅来自该发布者。
- 强名称提供了强大的完整性检查。通过.NET Framework安全检查可以保证程序集内容自上次构建以来未被更改。
是否可以使用强命名验证程序集作者?
是的,如上所述,强命名可以验证程序集的最新作者。但它不能验证原始作者。如果攻击者替换了您的程序集的强名称,那么只能验证您不是程序集的最新作者。如果他删除了强名称,则根本无法进行任何作者验证。
强名称程序集可以在多大程度上被验证以避免篡改?
下面的C#代码验证攻击者是否篡改了应用强名称时写入程序集的公钥令牌。它不能避免篡改,但可以检测某些类型的篡改。以下方法接受一个包含您的公钥令牌的字节数组,并将其与程序集的实际令牌进行比较。请注意,为使此技术有效,您选择的混淆器应加密包含您的公钥令牌的字符串,并且仅在使用时动态解密它。还要注意,您需要具有FullTrust权限才能使此代码工作,因为它在幕后使用反射。
private static bool IsPublicTokenOkay_Check(byte [] tokenExpected)
{
byte [] tokenCurrent = Assembly.GetExecutingAssembly().GetName().GetPublicKeyToken();
if (tokenExpected.Length == tokenCurrent.Length)
{
for (int i = 0; i < tokenCurrent.Length; i++)
if (tokenExpected[i] != tokenCurrent[i])
return false;
}
else
{
return false;
}
return true;
}
只要你运行的是.NET Framework 3.5 SP1之前的版本,你也可以强制验证强名称签名,以防止强名称被攻击者删除或在注册表中禁用强名称检查。以下代码演示了调用另一个名为NativeMethods的静态方法的过程,在此处将执行验证。
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 相当复杂 - 详细解释请参见
这篇博客文章。
[DllImport("mscoree.dll", CharSet=CharSet.Unicode)]
private static extern bool StrongNameSignatureVerificationEx(string wszFilePath,
byte fForceVerification,
ref byte pfWasVerified);
private NativeMethods()
{
}
public static bool CheckSignature(string assemblyName,
byte forceVerification,
ref byte wasVerified)
{
return StrongNameSignatureVerificationEx(assemblyName,
forceVerification,
ref wasVerified );
}
注意,默认情况下,这不适用于使用.NET 3.5 SP1或更高版本的应用程序,该版本具有
强名称绕过功能。可以通过向配置文件添加设置来
禁用此功能,使其适用于您的应用程序。但是,任何拥有读/写访问权限的攻击者都可以撤销您的决定。