65.9K
CodeProject 正在变化。 阅读更多。
Home

ASP.NET machineKey 生成器

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.81/5 (20投票s)

2006 年 12 月 4 日

5分钟阅读

viewsIcon

310290

downloadIcon

7838

一个 machineKey 生成器,允许在 ASP.NET 1.1 或 2.0 应用程序中使用静态密钥。

Sample Image - machineKey.png

引言

每当您使用 ViewState、Session、Forms 身份验证或其他加密和/或安全值时,ASP.NET 都会使用一组密钥进行加密和解密。通常,这些密钥是隐藏的,并在每次应用程序回收时由 ASP.NET 自动生成,但有时您可能希望指定一个特定的、持久的密钥。本文将解释为什么硬编码 machineKeys 是好的,以及如何为 ASP.NET 1.1 或 2.0 生成随机密钥。

为什么您需要一个持久的密钥

ASP.NET 使用两个密钥来加密、解密和验证 ViewState、Forms 身份验证票证和进程外 Session 数据中的数据。decryptionKey 用于身份验证票证和加密 ViewState 信息的加密和解密。validationKey 用于验证 ViewState 并确保其未被篡改,并为进程外会话存储生成唯一的应用程序特定会话 ID。

如果在 postback 之间密钥发生更改,您可能会遇到问题,例如,用于生成 ViewState 信息的一组密钥与页面之间不一致。如果发生这种情况,ViewState 验证将失败(因为 postback 后的 validationKey 将与 postback 前使用的密钥不同),用户将收到 Invalid_ViewState 错误。Postback 之间不同的密钥也可能意味着您的 Forms 身份验证票证将失败,需要用户重新登录到您的应用程序;进程外会话信息将丢失(因为会话 ID 会更改);加密的 ViewState 信息将无法解密和读取。

最后,如果您想使用 ASP.NET 2.0 的 Membership provider 加密密码,您必须提供一个静态密钥,否则您将收到一条错误消息:“您必须指定一个非自动生成的 machineKey 来以加密格式存储密码”。

为什么密钥会改变?

密钥在 postback 之间发生更改的频率可能比您预期的要高。一种情况是您正在运行一个 Web 场。默认情况下,用于创建 MAC 的 validationKey 是在应用程序池启动时由 ASP.NET 随机生成的。这确保了 validationKey 是唯一的,并且会定期更改。然而,由于密钥在服务器之间是不同的,如果您在服务器 A 上查看一个页面并将其 post 到服务器 B,当服务器 B 根据 viewstate 数据生成 MAC 时,该值将与页面最初由服务器 A 提供时的 MAC 值不匹配。因此,您将收到一个 Invalid_Viewstate 错误。

validationKeydecryptionKey(以及 MAC)不同的另一个原因是跨应用程序池。如果您查看在池 A 中运行的页面,然后 post 到池 B 中的另一个页面(例如,通过 Server.Transfer),密钥将不同,您将收到一个不匹配的错误。

最后,对于用户来说,validationKeydecryptionKey 可以在会话期间发生更改,如果应用程序池重新启动。假设某个用户正在查看您网站上的一个页面并填写表单。在此期间,某个系统管理员重新启动了池,从而生成了一个新密钥。当用户 post 该页面时,他们将收到一个 Invalid_Viewstate 错误。应用程序也可以在设置为闲置时关闭(默认是关闭闲置 20 分钟的池)。想象一下,一个用户查看了您网站上的一个页面,离开 10 分钟,然后花了 20 分钟填写页面上的表单。在此期间,您的网站上没有其他人,因此应用程序池超时并关闭。当用户最终 post 表单(查看后 30 分钟)时,应用程序池将重新启动,创建一个新的 validationKey,生成一个新的 MAC,注意到 MAC 值不匹配,并将 Invalid_Viewstate 错误奖励给用户的勤奋。

密钥放在哪里

因此,如果您想创建一组静态密钥,您需要将其放入 machine.configweb.configmachineKey 块中。您可以在 MSDN 上的 machineKey 元素处阅读更多相关信息。

validationKey 的最大长度为 64 字节。在 ASP.NET 1.1 中,加密算法是 3DES,decryptionKey 最大为 24 字节。ASP.NET 2.0 提供了一个名为 decryption 的属性,允许用户指定用于解密数据的哈希算法。AES 算法是最佳选择,支持 32 字节的 decryptionKey

请注意,下面的示例包含 [...],表示为提高可读性而删除了某些字符。密钥的实际值是长而连续的十六进制编码字符串。不要将下面的示例逐字复制并粘贴到您的 web.config 中——而是下载并运行示例项目,或者通过 在线演示生成随机密钥。

ASP.NET 1.1 版本

<machineKey 
validationKey="C3BB96E9C96[...]3F7ACCB7E7DEA"
decryptionKey="E5E046B77ED2C[...]C13205DBA8E3ECEC4BDE346"
validation="SHA1"
/>

ASP.NET 2.0 版本

<machineKey 
validationKey="3DC93913A3E7998AE43[...]C519574359262"
decryptionKey="9470AD8F914387CBE0[...]ABA8A0DB762"
validation="SHA1" decryption="AES"
/>

生成随机密钥

现在我们已经讨论了 machineKey 部分中的密钥,让我们快速看一下一些生成随机密钥的代码。这很简单。

下面的函数接受一个字节数,使用 .NET Crypto 库生成一个随机数字的字节数组,并使用 StringBuilder 构建并返回一个十六进制编码的字符串。由于随机数字是十六进制编码的,一个 24 字节的随机密钥将产生一个 48 个字符的十六进制编码字符串。

public string getRandomKey(int bytelength)
{
    byte[] buff = new byte;
    RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
    rng.GetBytes(buff);
    StringBuilder sb = new StringBuilder(bytelength * 2);
    for (int i = 0; i < buff.Length; i++)
        sb.Append(string.Format("{0:X2}", buff[i]));
    return sb.ToString();
}

现在我们有两个简单的函数,它们使用 getRandomKey 函数来构建并返回一个完整的 machineKey 部分,可以将其粘贴到 web.config 中。

public string getASPNET20machinekey()
{
    StringBuilder aspnet20machinekey = new StringBuilder();
    string key64byte = getRandomKey(64);
    string key32byte = getRandomKey(32);
    aspnet20machinekey.Append("<machineKey \n");
    aspnet20machinekey.Append("validationKey=\"" + key64byte + "\"\n");
    aspnet20machinekey.Append("decryptionKey=\"" + key32byte + "\"\n");
    aspnet20machinekey.Append("validation=\"SHA1\" decryption=\"AES\"\n");
    aspnet20machinekey.Append("/>\n");
    return aspnet20machinekey.ToString();
}

public string getASPNET11machinekey()
{
    StringBuilder aspnet11machinekey = new StringBuilder();
    string key64byte = getRandomKey(64);
    string key24byte = getRandomKey(24);

    aspnet11machinekey.Append("<machineKey ");
    aspnet11machinekey.Append("validationKey=\"" + key64byte + "\"\n");
    aspnet11machinekey.Append("decryptionKey=\"" + key24byte + "\"\n");
    aspnet11machinekey.Append("validation=\"SHA1\"\n");
    aspnet11machinekey.Append("/>\n");
    return aspnet11machinekey.ToString();
}

现在我们所要做的就是调用 getASPNET11machinekeygetASPNET20machinekey 函数来获取我们选择的环境的随机 machineKey 部分。

示例应用程序

示例应用程序是一个 ASP.NET 1.1 Web 项目,其中包含一个 machineKey.aspx 文件,演示了上述功能。如果您想自己生成密钥或只是想看看它是如何工作的,您还可以 在此处查看实时演示

结论

我们已经讨论了 decryptionKeyvalidationKey,回顾了它们如何改变以及可能带来的问题,并讨论了如何生成和部署静态密钥以避免问题。希望这能在您下次遇到 ViewState 或其他相关问题时有所帮助。

相关阅读

您可以在此处阅读更多关于 machineKey 及其影响的信息:

ASP.NET machineKey Generator - CodeProject - 代码之家
© . All rights reserved.