加密解密ASP.NET
Encryption and decryption ASP.NET
我一直在google寻找一种简单的加密和解密方法来存储密码。我不是在寻找非常复杂的加密,所以我想这就是很难找到的原因。
谁有简单的加解密方法可以分享给我吗?
例如,您应该使用 SHA256 散列密码。要检查密码有效性,您对从用户收到的密码进行哈希处理,并将其与存储在数据库中的哈希值进行比较。
也就是说,您应该确保通过 SSL 发送密码,否则它们可能会被捕获。如果您自己的 OS 不安全,密码在到达时可能会以明文形式被捕获。
当您的网站位于 Intranet 上时,您最好使用 Windows 集成身份验证。对于 Internet,OAuth 可能是更好的选择。
感谢@philsoady 指出 https://security.stackexchange.com/questions/35250/hmacsha512-versus-rfc2898derivebytes-for-password-hash 进一步阅读。
为什么应该使用散列而不是加密:
如果您使用加密,那么您将需要一个密钥。可以获取此密钥并用于解密您的密码。您组织内的人员很可能有权访问此密钥。这意味着每个人都有可能知道您用户的密码。
哈希有什么不同?
散列被设计为一种单向线性变换。因此,您无法返回并获取实际密码。可以通过以下方式演示一个简单的哈希算法:使用密码除以 6 的余数。假设您的密码是 10。您将在数据库中存储 4,因为 10/6 的余数是 4。如果您在数据库中看到 4,你不能倒退并计算出你有 10,因为它也可能是 4 或 16(或无限多的其他)。但是,通过传入 10,您可以验证这与数据库中存储的 4 相同。您可能会注意到这里的一个固有缺陷。如果您使用 16 作为您的密码,它仍然会在数据库中匹配。这称为碰撞。
建议您使用大于 SHA128(128 位输出)的散列算法,因为在发现冲突之前搜索在计算上是不可行的。 SHA 算法专为速度而设计,因此这些算法对您来说仍然足够快(您说它重量轻)。另外,一些人生成了一组已知的流行密码及其哈希值(通常称为 rainbow tables
),用于快速交叉引用存储的值。
为了提高安全性,为每个用户创建一个唯一值(通常称为 salt
),您应该在哈希之前将其附加到密码的开头或结尾。例如,salt 值为 salt
,密码为 password
,因此我们将散列 saltpassword
并存储结果。然后当用户再次登录时,我们会将生成的哈希值与存储的值进行比较。这样做更好的原因是在两个用户具有相同密码的情况下,他们将具有两个不同的唯一哈希值。
一个小代码示例:
using System.Security.Cryptography;
private string HashPassword(string password, string salt)
{
string hashedString = CryptoConfig.CreateFromName("SHA256")
.ComputeHash(salt+password);
return hashedString;
}
基本上,使用加密意味着可以发现密码。使用散列意味着你无法切实找出它们是什么,只能找到潜在的碰撞(除非你真的很幸运)。
正如 oscar132 在评论中解释的那样,您不应该尝试重新发明会员资格。
ASP.NET 有一个非常好的会员提供程序作为默认选项,不需要那么多配置。它拥有良好密码管理所需的一切:用户管理、密码重置、集成 Web 控件……
它也没有使用非常不安全的加密方法,而是使用已经推荐的 SHA256 方法对密码进行哈希处理,并可选择使用自定义提供程序来增强加密算法,如 PBKDF2 或 bcrypt。
即使您的项目已经在进行中,添加对它的支持也不难。 Visual Studio 默认支持将 asp.net 网站升级为 asp.net 实现成员资格的 Web 表单应用程序。
真的不是 SO 问题,但以防其他人发现这个问题。
有些做和不做。这里可能缺少本土网站。
- 不存储密码,存储单向哈希。尽可能对它们进行编码。
- 不要使用 HMacSHA* 作为算法,使用 BCRPT、SCRYPT 或 RFC2898DerivedBytes(PBKDF2) 作为密码。 SHA 太快,不适合密码散列。
- 使用 SALT
- 例如在您的环境中更喜欢经过良好测试和接受的标准工具 ASP.Net Identity
- 请求用户密码时始终使用 SSL
- 如果你必须(你真的确定)加密和解密有一个机器密钥/解密密钥策略。加密取决于密钥的安全性。
如果严重的应用考虑使用 SCyrpt for c#
标准 c# 中用于编码密码的 最低限度 应该是这样的
以下使用 Rfc2898.
a) 将编码后的密码和随机 SALT 存储在您的数据库中。
b) 使用至少需要 250 毫秒的成本。
c) 将用户提供的密码与存储的 SALT 与相同的例程进行比较,并比较哈希值。
private string PasswordEncode(string password, byte[] salt ) {
var deriver2898 = new Rfc2898DeriveBytes(password, salt,64000); // approx 300msecs
byte[] hash = deriver2898.GetBytes(20); //
// return hash;
// If you dont like storing bytes, use a string
return Convert.ToBase64String(hash);
}
// himalayan pink rock salt... the best kind
public byte[] GenerateSalt(int size = 64) {
using (var crypto = new RNGCryptoServiceProvider()) {
var bytes = new byte[size];
crypto.GetBytes(bytes); //get a bucket of very random bytes
return bytes;
}
}
如果您在此阶段仍然确信需要加密,则使用 Microsoft 的一种对称算法。 EG AesManaged
/// <summary>
/// Encrypt using preferred provider.
/// </summary>
/// <typeparam name="T">AesManaged,TripleDESCryptoServiceProvider,RijndaelManaged</typeparam>
/// <param name="value">Value to be encrypted</param>
/// <param name="decryptionKey">secret key .. see machine key descryptionKey</param>
/// <param name="salt">salt for process</param>
/// <returns></returns>
public string Encrypt<T>(string value, string salt, string decryptionKey)
where T : SymmetricAlgorithm, new() {
var derivedKey = GenerateKey(decryptionKey, salt);
SymmetricAlgorithm algorithm = new T();
byte[] rgbKey = derivedKey.GetBytes(algorithm.KeySize >> 3);
byte[] rgbIv = derivedKey.GetBytes(algorithm.BlockSize >> 3);
ICryptoTransform transform = algorithm.CreateEncryptor(rgbKey, rgbIv);
using (var buffer = new MemoryStream()) {
using (var stream = new CryptoStream(buffer, transform, CryptoStreamMode.Write)) {
using (var writer = new StreamWriter(stream, Encoding.Unicode)) {
writer.Write(value);
}
}
// before finished with the buffer return, now as the stream is now closed
return Convert.ToBase64String(buffer.ToArray());
}
}
public string Decrypt<T>(string text, string salt, string decryptionKey)
where T : SymmetricAlgorithm, new() {
// could catch errors here, and return a null string. ?
// "CryptographicException: Padding is invalid and cannot be removed"
// can occur if there is a coding problem , such as invalid key or salt passed to this routine.
var derivedKey = GenerateKey(decryptionKey, salt);
SymmetricAlgorithm algorithm = new T();
byte[] rgbKey = derivedKey.GetBytes(algorithm.KeySize >> 3);
byte[] rgbIv = derivedKey.GetBytes(algorithm.BlockSize >> 3);
ICryptoTransform transform = algorithm.CreateDecryptor(rgbKey, rgbIv);
using (var buffer = new MemoryStream(Convert.FromBase64String(text))) {
using (var stream = new CryptoStream(buffer, transform, CryptoStreamMode.Read)) {
using (var reader = new StreamReader(stream, Encoding.Unicode)) {
return reader.ReadToEnd(); // error here implies wrong keys supplied , and code or environment problem.. NASTY issue
}
}
}
}
public DeriveBytes GenerateKey(string salt, string decryptionKey) {
// generate the key from the shared secret and the salt
var saltAsByteArray = salt.UTF8StringToByteArray();
var key = new Rfc2898DeriveBytes(decryptionKey, saltAsByteArray);
return key;
}
示例调用:加密和解密。再加上考虑,how to get machine key and use as key here
Encrypt<AesManaged>(password, salt, decryptionKey);
Decrypt<AesManaged>(encryptedPassword, salt, decryptionKey);
我一直在google寻找一种简单的加密和解密方法来存储密码。我不是在寻找非常复杂的加密,所以我想这就是很难找到的原因。
谁有简单的加解密方法可以分享给我吗?
例如,您应该使用 SHA256 散列密码。要检查密码有效性,您对从用户收到的密码进行哈希处理,并将其与存储在数据库中的哈希值进行比较。
也就是说,您应该确保通过 SSL 发送密码,否则它们可能会被捕获。如果您自己的 OS 不安全,密码在到达时可能会以明文形式被捕获。
当您的网站位于 Intranet 上时,您最好使用 Windows 集成身份验证。对于 Internet,OAuth 可能是更好的选择。
感谢@philsoady 指出 https://security.stackexchange.com/questions/35250/hmacsha512-versus-rfc2898derivebytes-for-password-hash 进一步阅读。
为什么应该使用散列而不是加密:
如果您使用加密,那么您将需要一个密钥。可以获取此密钥并用于解密您的密码。您组织内的人员很可能有权访问此密钥。这意味着每个人都有可能知道您用户的密码。
哈希有什么不同?
散列被设计为一种单向线性变换。因此,您无法返回并获取实际密码。可以通过以下方式演示一个简单的哈希算法:使用密码除以 6 的余数。假设您的密码是 10。您将在数据库中存储 4,因为 10/6 的余数是 4。如果您在数据库中看到 4,你不能倒退并计算出你有 10,因为它也可能是 4 或 16(或无限多的其他)。但是,通过传入 10,您可以验证这与数据库中存储的 4 相同。您可能会注意到这里的一个固有缺陷。如果您使用 16 作为您的密码,它仍然会在数据库中匹配。这称为碰撞。
建议您使用大于 SHA128(128 位输出)的散列算法,因为在发现冲突之前搜索在计算上是不可行的。 SHA 算法专为速度而设计,因此这些算法对您来说仍然足够快(您说它重量轻)。另外,一些人生成了一组已知的流行密码及其哈希值(通常称为 rainbow tables
),用于快速交叉引用存储的值。
为了提高安全性,为每个用户创建一个唯一值(通常称为 salt
),您应该在哈希之前将其附加到密码的开头或结尾。例如,salt 值为 salt
,密码为 password
,因此我们将散列 saltpassword
并存储结果。然后当用户再次登录时,我们会将生成的哈希值与存储的值进行比较。这样做更好的原因是在两个用户具有相同密码的情况下,他们将具有两个不同的唯一哈希值。
一个小代码示例:
using System.Security.Cryptography;
private string HashPassword(string password, string salt)
{
string hashedString = CryptoConfig.CreateFromName("SHA256")
.ComputeHash(salt+password);
return hashedString;
}
基本上,使用加密意味着可以发现密码。使用散列意味着你无法切实找出它们是什么,只能找到潜在的碰撞(除非你真的很幸运)。
正如 oscar132 在评论中解释的那样,您不应该尝试重新发明会员资格。
ASP.NET 有一个非常好的会员提供程序作为默认选项,不需要那么多配置。它拥有良好密码管理所需的一切:用户管理、密码重置、集成 Web 控件……
它也没有使用非常不安全的加密方法,而是使用已经推荐的 SHA256 方法对密码进行哈希处理,并可选择使用自定义提供程序来增强加密算法,如 PBKDF2 或 bcrypt。
即使您的项目已经在进行中,添加对它的支持也不难。 Visual Studio 默认支持将 asp.net 网站升级为 asp.net 实现成员资格的 Web 表单应用程序。
真的不是 SO 问题,但以防其他人发现这个问题。 有些做和不做。这里可能缺少本土网站。
- 不存储密码,存储单向哈希。尽可能对它们进行编码。
- 不要使用 HMacSHA* 作为算法,使用 BCRPT、SCRYPT 或 RFC2898DerivedBytes(PBKDF2) 作为密码。 SHA 太快,不适合密码散列。
- 使用 SALT
- 例如在您的环境中更喜欢经过良好测试和接受的标准工具 ASP.Net Identity
- 请求用户密码时始终使用 SSL
- 如果你必须(你真的确定)加密和解密有一个机器密钥/解密密钥策略。加密取决于密钥的安全性。
如果严重的应用考虑使用 SCyrpt for c# 标准 c# 中用于编码密码的 最低限度 应该是这样的 以下使用 Rfc2898.
a) 将编码后的密码和随机 SALT 存储在您的数据库中。
b) 使用至少需要 250 毫秒的成本。
c) 将用户提供的密码与存储的 SALT 与相同的例程进行比较,并比较哈希值。
private string PasswordEncode(string password, byte[] salt ) {
var deriver2898 = new Rfc2898DeriveBytes(password, salt,64000); // approx 300msecs
byte[] hash = deriver2898.GetBytes(20); //
// return hash;
// If you dont like storing bytes, use a string
return Convert.ToBase64String(hash);
}
// himalayan pink rock salt... the best kind
public byte[] GenerateSalt(int size = 64) {
using (var crypto = new RNGCryptoServiceProvider()) {
var bytes = new byte[size];
crypto.GetBytes(bytes); //get a bucket of very random bytes
return bytes;
}
}
如果您在此阶段仍然确信需要加密,则使用 Microsoft 的一种对称算法。 EG AesManaged
/// <summary>
/// Encrypt using preferred provider.
/// </summary>
/// <typeparam name="T">AesManaged,TripleDESCryptoServiceProvider,RijndaelManaged</typeparam>
/// <param name="value">Value to be encrypted</param>
/// <param name="decryptionKey">secret key .. see machine key descryptionKey</param>
/// <param name="salt">salt for process</param>
/// <returns></returns>
public string Encrypt<T>(string value, string salt, string decryptionKey)
where T : SymmetricAlgorithm, new() {
var derivedKey = GenerateKey(decryptionKey, salt);
SymmetricAlgorithm algorithm = new T();
byte[] rgbKey = derivedKey.GetBytes(algorithm.KeySize >> 3);
byte[] rgbIv = derivedKey.GetBytes(algorithm.BlockSize >> 3);
ICryptoTransform transform = algorithm.CreateEncryptor(rgbKey, rgbIv);
using (var buffer = new MemoryStream()) {
using (var stream = new CryptoStream(buffer, transform, CryptoStreamMode.Write)) {
using (var writer = new StreamWriter(stream, Encoding.Unicode)) {
writer.Write(value);
}
}
// before finished with the buffer return, now as the stream is now closed
return Convert.ToBase64String(buffer.ToArray());
}
}
public string Decrypt<T>(string text, string salt, string decryptionKey)
where T : SymmetricAlgorithm, new() {
// could catch errors here, and return a null string. ?
// "CryptographicException: Padding is invalid and cannot be removed"
// can occur if there is a coding problem , such as invalid key or salt passed to this routine.
var derivedKey = GenerateKey(decryptionKey, salt);
SymmetricAlgorithm algorithm = new T();
byte[] rgbKey = derivedKey.GetBytes(algorithm.KeySize >> 3);
byte[] rgbIv = derivedKey.GetBytes(algorithm.BlockSize >> 3);
ICryptoTransform transform = algorithm.CreateDecryptor(rgbKey, rgbIv);
using (var buffer = new MemoryStream(Convert.FromBase64String(text))) {
using (var stream = new CryptoStream(buffer, transform, CryptoStreamMode.Read)) {
using (var reader = new StreamReader(stream, Encoding.Unicode)) {
return reader.ReadToEnd(); // error here implies wrong keys supplied , and code or environment problem.. NASTY issue
}
}
}
}
public DeriveBytes GenerateKey(string salt, string decryptionKey) {
// generate the key from the shared secret and the salt
var saltAsByteArray = salt.UTF8StringToByteArray();
var key = new Rfc2898DeriveBytes(decryptionKey, saltAsByteArray);
return key;
}
示例调用:加密和解密。再加上考虑,how to get machine key and use as key here
Encrypt<AesManaged>(password, salt, decryptionKey);
Decrypt<AesManaged>(encryptedPassword, salt, decryptionKey);