Machine.config 文件中节点<machineKey>的强随机生成
<machineKey>这个节允许你设置用于加密数据和创建数字签名的服务器特定的密钥。ASP.NET自动使用它来保护表单验证Cookie,你也可以将它用于受保护的视图状态数据。同时,这个密钥还用于验证进程外的会话状态提供程序。
如果你在使用Web集群并在多台计算机上运行同一个应用程序,如果对页面的请求由一台计算机处理,而页面回发又由另一台计算机处理,第二个服务器就不能解密来自第一台服务器的视图状态和表单Cookie。这个问题之所以会发生,是因为两台服务器使用了不同的密钥。
要解决这个问题,你必须显式的在machine.config文件中定义这个密钥:
<machineKey validationKey = "6efa......." decryptionKey = "ACE09876A7......." />
其中,validationKey 的值可以是48到128个字符长,强烈建议使用可用的最长密钥。decryptionKey 的值可以是16到48字符长,建议使用48字符长。
自己去手动创建验证密钥和解密密钥并没有多大的意义。如果你这么做的话,它们可能随机性不足,这就可能允许某种类型的攻击。更好的办法是使用代码和.NET加密类(System.Security.Cryptography 命名空间)生成随机密钥,代码如下:
using System;
using System.Security.Cryptography;
using System.Text;
/// <summary>
/// 各类工具
/// </summary>
public class Tools
{
/// <summary>
/// 使用加密服务提供程序实现加密生成随机数
/// </summary>
/// <param name="length"></param>
/// <returns>16进制格式字符串</returns>
public static string CreateMachineKey(int length)
{
// 要返回的字符格式为16进制,byte最大值255
// 需要2个16进制数保存1个byte,因此除2
byte[] random = new byte[length / 2];
// 使用加密服务提供程序 (CSP) 提供的实现来实现加密随机数生成器 (RNG)
RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
// 用经过加密的强随机值序列填充字节数组
rng.GetBytes(random);
StringBuilder machineKey = new StringBuilder(length);
for (int i = 0; i < random.Length; i++)
{
machineKey.Append(string.Format("{0:X2}", random[i]));
}
return machineKey.ToString();
}
}
调用:
string decryptionKey = Tools.CreateMachineKey(48);
string validationKey = Tools.CreateMachineKey(128);
使用这个方法可以创建需要的密钥,然后可以复制这些信息并粘贴到Web集群中每台计算机的machine.config文件中,这要比手工创建密钥更安全,更便捷。