gpt4 book ai didi

hash - 存储散列密码 - base64,或十六进制字符串,还是其他什么?

转载 作者:行者123 更新时间:2023-12-02 03:31:06 26 4
gpt4 key购买 nike

我使用 .NET System.Security.Cryptography 类对密码进行哈希处理。它有一些哈希算法,例如MD5、SHA1、SHA256、SHA384、SHA512

生成的哈希值是一个字节数组。我应该将其转换为十六进制字符串进行存储,或者 Convert.ToBase64String(),还是其他东西? (我更喜欢 Base64,因为它比十六进制短)。

顺便说一句,有这么多哈希算法可供选择,我随机选择了 SHA384,但是有一个“更好”或适合该任务的吗?

欢迎评论。

阅读前八条评论后更新:
根据我所做的答案和进一步阅读,MD5、SHA1 似乎或多或少是等效的(SHA1 稍微更安全)。 SHA256、384、512 按递增顺序提供更好的安全性。

由于我不需要诺克斯堡(这是一个内部公司系统,没有网址、浏览器、互联网、内联网或外联网),我将绕过“加盐”业务 - 我想如果有人可以窃取密码表,他们也可能窃取其他表中的实际数据。

但我会保留“盐”的概念以供将来引用;不确定在散列之前是否应该在密码后面附加盐(在末尾)或在密码前面(在前面),这会有所不同吗?另外,我正在考虑使用密码本身的前几个字符作为盐,以避免额外的字段来存储它,但我想它不够长 - 并且盐应该足够长。

共识认为,base64 转换是存储和比较的合理选择。假设最大密码长度为 15 个字符,我仍然需要弄清楚散列存储所需的最大数据库列长度是多少。也许是 Varchar(64)?

感谢大家的贡献。

最佳答案

即使您的解决方案不是诺克斯堡,您也应该勤奋并实现加盐。因为许多人在其他地方重复使用他们的密码,如果攻击者选择将破解的密码数据库用于其他目的,那么入侵将会在您的组织外部造成额外的损害。

加盐使字典攻击更加昂贵。通过决定使用什么盐的大小,您可以微调您的机会。以下是 Bruce Schneier 的《应用密码学》中的引述:

"Salt isn't a panacea; increasing the number of salt bits won't solve everything. Salt only protects against general dictionary attacks on a password file, not a concerted attack on a single password. It protects people who have the same password on multiple machines, but doesn't make poorly chosen passwords any better."

这是一个 C# 示例。这并不难。您可以选择要使用的盐大小和哈希函数。免责声明:使用类似 bcrypt 的内容如果您真的关心密码完整性。


using System;
using System.IO;
using System.Reflection;
using System.Security.Cryptography;
using System.Text;

public class PassHash {
private static readonly RandomNumberGenerator rng = RandomNumberGenerator.Create();
public static readonly int DefaultSaltSize = 8; // 64-bit salt
public readonly byte[] Salt;
public readonly byte[] Passhash;

internal PassHash(byte[] salt, byte[] passhash) {
Salt = salt;
Passhash = passhash;
}

public override String ToString() {
return String.Format("{{'salt': '{0}', 'passhash': '{1}'}}",
Convert.ToBase64String(Salt),
Convert.ToBase64String(Passhash));
}

public static PassHash Encode<HA>(String password) where HA : HashAlgorithm {
return Encode<HA>(password, DefaultSaltSize);
}

public static PassHash Encode<HA>(String password, int saltSize) where HA : HashAlgorithm {
return Encode<HA>(password, GenerateSalt(saltSize));
}

private static PassHash Encode<HA>(string password, byte[] salt) where HA : HashAlgorithm {
BindingFlags publicStatic = BindingFlags.Public | BindingFlags.Static;
MethodInfo hasher_factory = typeof (HA).GetMethod("Create", publicStatic, Type.DefaultBinder, Type.EmptyTypes, null);
using (HashAlgorithm hasher = (HashAlgorithm) hasher_factory.Invoke(null, null))
{
using (MemoryStream hashInput = new MemoryStream())
{
hashInput.Write(salt, 0, salt.Length);
byte[] passwordBytes = Encoding.UTF8.GetBytes(password);
hashInput.Write(passwordBytes, 0, passwordBytes.Length);
hashInput.Seek(0, SeekOrigin.Begin);
byte[] passhash = hasher.ComputeHash(hashInput);
return new PassHash(salt, passhash);
}
}
}

private static byte[] GenerateSalt(int saltSize) {
// This generates salt.
// Rephrasing Schneier:
// "salt" is a random string of bytes that is
// combined with password bytes before being
// operated by the one-way function.
byte[] salt = new byte[saltSize];
rng.GetBytes(salt);
return salt;
}

public static bool Verify<HA>(string password, byte[] salt, byte[] passhash) where HA : HashAlgorithm {
// OMG: I don't know how to compare byte arrays in C#.
return Encode<HA>(password, salt).ToString() == new PassHash(salt, passhash).ToString();
}
}

用法:

新用户提交其凭据。

PassHash ph = PassHash.Encode<SHA384>(new_user_password);

商店ph.Salt & ph.Passhash某处...稍后,当用户再次登录时,您会查找包含 salt 和 passhash 的用户记录,然后执行以下操作:

PassHash.Verify<SHA384>(user_login_password, user_rec.salt, user_rec.passhash)

}

关于hash - 存储散列密码 - base64,或十六进制字符串,还是其他什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/949271/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com