我想在ASP.NET MVC应用程序中加密一些数据,以防止用户篡改它 . 我可以使用Cryptography类来进行实际的加密/解密,没问题 . 主要问题是找出存储加密密钥的位置并管理对其的更改 .
由于ASP.NET已经为各种事物维护了一个machineKey(ViewData加密等),我想知道是否有任何ASP.NET函数允许我使用machineKey加密/解密我自己的数据?这样我就不必设计自己的密钥管理系统 .
您可以重用MembershipProvider.EncryptPassword方法,后者又使用MachineKeySection类的一些(不幸的是内部)加密方法 .
使用.NET Framwork 4.5,您应该使用新的API:
public class StringProtector { private const string Purpose = "Authentication Token"; public string Protect(string unprotectedText) { var unprotectedBytes = Encoding.UTF8.GetBytes(unprotectedText); var protectedBytes = MachineKey.Protect(unprotectedBytes, Purpose); var protectedText = Convert.ToBase64String(protectedBytes); return protectedText; } public string Unprotect(string protectedText) { var protectedBytes = Convert.FromBase64String(protectedText); var unprotectedBytes = MachineKey.Unprotect(protectedBytes, Purpose); var unprotectedText = Encoding.UTF8.GetString(unprotectedBytes); return unprotectedText; } }
理想情况下,“目的”应该是已知的一次有效值以防止伪造 .
ASP.NET 4.0中的新MachineKey类完全符合您的要求 .
例如:
public static class StringEncryptor { public static string Encrypt(string plaintextValue) { var plaintextBytes = Encoding.UTF8.GetBytes(plaintextValue); return MachineKey.Encode(plaintextBytes, MachineKeyProtection.All); } public static string Decrypt(string encryptedValue) { try { var decryptedBytes = MachineKey.Decode(encryptedValue, MachineKeyProtection.All); return Encoding.UTF8.GetString(decryptedBytes); } catch { return null; } } }
UPDATE :如上所述here,请注意如何使用它,或者您可以允许某人伪造表单身份验证令牌 .
我想不是直接的 . 我不记得我从哪里得到这个,可能是Reflector和一些博客的组合 .
public abstract class MyAwesomeClass { private static byte[] cryptKey; private static MachineKeySection machineKeyConfig = (MachineKeySection)ConfigurationManager .GetSection("system.web/machineKey"); // ... snip ... static MyAwesomeClass() { string configKey; byte[] key; configKey = machineKeyConfig.DecryptionKey; if (configKey.Contains("AutoGenerate")) { throw new ConfigurationErrorsException( Resources.MyAwesomeClass_ExplicitAlgorithmRequired); } key = HexStringToByteArray(configKey); cryptKey = key; } // ... snip ... protected static byte[] Encrypt(byte[] inputBuffer) { SymmetricAlgorithm algorithm; byte[] outputBuffer; if (inputBuffer == null) { throw new ArgumentNullException("inputBuffer"); } algorithm = GetCryptAlgorithm(); using (var ms = new MemoryStream()) { algorithm.GenerateIV(); ms.Write(algorithm.IV, 0, algorithm.IV.Length); using (var cs = new CryptoStream( ms, algorithm.CreateEncryptor(), CryptoStreamMode.Write)) { cs.Write(inputBuffer, 0, inputBuffer.Length); cs.FlushFinalBlock(); } outputBuffer = ms.ToArray(); } return outputBuffer; } protected static byte[] Decrypt(string input) { SymmetricAlgorithm algorithm; byte[] inputBuffer, inputVectorBuffer, outputBuffer; if (input == null) { throw new ArgumentNullException("input"); } algorithm = GetCryptAlgorithm(); outputBuffer = null; try { inputBuffer = Convert.FromBase64String(input); inputVectorBuffer = new byte[algorithm.IV.Length]; Array.Copy( inputBuffer, inputVectorBuffer, inputVectorBuffer.Length); algorithm.IV = inputVectorBuffer; using (var ms = new MemoryStream()) { using (var cs = new CryptoStream( ms, algorithm.CreateDecryptor(), CryptoStreamMode.Write)) { cs.Write( inputBuffer, inputVectorBuffer.Length, inputBuffer.Length - inputVectorBuffer.Length); cs.FlushFinalBlock(); } outputBuffer = ms.ToArray(); } } catch (FormatException e) { throw new CryptographicException( "The string could not be decoded.", e); } return outputBuffer; } // ... snip ... private static SymmetricAlgorithm GetCryptAlgorithm() { SymmetricAlgorithm algorithm; string algorithmName; algorithmName = machineKeyConfig.Decryption; if (algorithmName == "Auto") { throw new ConfigurationErrorsException( Resources.MyAwesomeClass_ExplicitAlgorithmRequired); } switch (algorithmName) { case "AES": algorithm = new RijndaelManaged(); break; case "3DES": algorithm = new TripleDESCryptoServiceProvider(); break; case "DES": algorithm = new DESCryptoServiceProvider(); break; default: throw new ConfigurationErrorsException( string.Format( CultureInfo.InvariantCulture, Resources.MyAwesomeClass_UnrecognizedAlgorithmName, algorithmName)); } algorithm.Key = cryptKey; return algorithm; } private static byte[] HexStringToByteArray(string str) { byte[] buffer; if (str == null) { throw new ArgumentNullException("str"); } if (str.Length % 2 == 1) { str = '0' + str; } buffer = new byte[str.Length / 2]; for (int i = 0; i < buffer.Length; ++i) { buffer[i] = byte.Parse( str.Substring(i * 2, 2), NumberStyles.HexNumber, CultureInfo.InvariantCulture); } return buffer; } }
买者自负!
如果您使用的是3.5或更早版本,则可以避免大量代码并执行此操作:
public static string Encrypt(string cookieValue) { return FormsAuthentication.Encrypt(new FormsAuthenticationTicket(1, string.Empty, DateTime.Now, DateTime.Now.AddMinutes(20160), true, cookieValue)); } public static string Decrypt(string encryptedTicket) { return FormsAuthentication.Decrypt(encryptedTicket).UserData; }
我的一位同事和我进行了交谈,我认为对于自定义cookie这样做是相当合理的,如果不是因为一般的加密需求 .
5 回答
您可以重用MembershipProvider.EncryptPassword方法,后者又使用MachineKeySection类的一些(不幸的是内部)加密方法 .
使用.NET Framwork 4.5,您应该使用新的API:
理想情况下,“目的”应该是已知的一次有效值以防止伪造 .
ASP.NET 4.0中的新MachineKey类完全符合您的要求 .
例如:
UPDATE :如上所述here,请注意如何使用它,或者您可以允许某人伪造表单身份验证令牌 .
我想不是直接的 . 我不记得我从哪里得到这个,可能是Reflector和一些博客的组合 .
买者自负!
如果您使用的是3.5或更早版本,则可以避免大量代码并执行此操作:
我的一位同事和我进行了交谈,我认为对于自定义cookie这样做是相当合理的,如果不是因为一般的加密需求 .