使用 x/crypto/bcrypt 时,可以在生成密码哈希时使用自定义的盐值。

huangapple go评论72阅读模式
英文:

Go x/crypto/bcrypt: Using a custom salt when generating the password hash

问题

我正在尝试为一个Go服务器实现一个基本的身份验证系统,其中包含具有多个由服务器生成的密码(实质上是令牌)的用户,这些密码必须安全地存储在数据库中。

一种实现方式是使用单向函数和全局唯一的盐对密码进行哈希处理。

然而,在我的情况下,由于用户有多个密码,这对身份验证造成了问题;用户的每个密码可能有不同的盐,因此服务器需要在数据库中迭代密码,使用与数据库中的盐相同的盐对提供的密码进行哈希处理,然后进行比较。这似乎不太高效。

另一种方法是放宽盐的“全局唯一”约束,在用户创建时随机生成一个盐,并将其用于该用户的所有密码。这样,我只需要对用户提供的密码进行一次哈希处理,然后可以使用SQL查询进行身份验证。这也是这个相关问题中建议的解决方案。

然而,Go的x/crypto/bcrypt包没有公开一个使用自定义盐对密码进行哈希处理的函数,它的盐生成是私有的。这样做有充分的理由吗?使用一个公共盐来处理用户的所有密码是否存在漏洞?

这个问题似乎很常见,因为像GitHub和GitLab这样的网站需要处理个人访问令牌的存储,然而,GitLab(默认情况下)只是对它们生成的令牌进行sha256哈希处理

英文:

I am trying to implement a basic authentication system for a Go server that consists of users with multiple server-generated passwords (tokens essentially) which must be securely stored in a database.

One way of accomplishing this would be to hash the passwords with a one-way function and a globally unique salt.

However, since users have multiple passwords in my case, this creates a problem for authentication; each of the user's passwords would likely have a different salt, so the server would need to iterate through the passwords in the database, hash the supplied password using the same salt as the one in the database, and then compare. This does not seem efficient.

Alternatively, I was thinking that I could relax the "globally unique" constraint on the salt and randomly generate a salt when the user is created, and use it for all that user's passwords. With this, I would only need to hash the user-supplied password once, and could then use an SQL query to perform authentication. This is also the solution suggested in this related question.

However, the Go x/crypto/bcrypt package does not expose a function which hashes passwords with a custom salt, its salt generation is private. Is this for a good reason? Are there vulnerabilities with this approach of using a common salt for all of a user's passwords?

This problem seems common enough given that sites like GitHub and GitLab would have to deal with it for their personal access token storage, yet it appears that GitLab (by default) simply performs a sha256 hashing on their generated tokens.

答案1

得分: 2

按设计,每个哈希都有自己的盐,这些盐以字符串形式与数据库一起存储,包括盐、密码哈希和bcrypt等。似乎所有或大多数较新一代的加密算法都是这样做的,因此每个哈希都必须单独破解。如果你想在代码中存储一些内容,我建议在每个密码中添加一个"pepper",然后让它们在数据库中的盐是唯一的。

你担心遍历每个密码的效率问题,但我认为你不必担心,安全性可能比登录效率更重要。只需将用户的登录会话存储一段时间即可。

是否存在漏洞

嗯,如果这是一个答案的话,bcrypt本身被认为是有漏洞的。

我认为你应该选择argon2id,因为它是当今被认为是"好"的算法,而且由于你的程序是新的,所以这是一个不错的选择。
https://pkg.go.dev/golang.org/x/crypto/argon2
这是一个包装器,就Go语言的加密而言是安全的,并且非常容易使用:
https://github.com/alexedwards/argon2id

如果你想要使用令牌,你可能应该使用UUIDs。

英文:

By design each hash would have it's own salt, this is stored in the database. as a string with the salt, password hash, bcrypt passes etc. It appears all or most newer gen cryptography does this so each hash would have to be cracked individually. If you want something stored in your code I'd add a pepper to every password and then let their salts be unique in the db.

You're worried about efficiency of iterating over each password but I wouldn't be, security is probably better than your login efficiency. Just store their login session for x days?

> Are there vulnerabilities

Well yes, bcrypt itself is considered vulnerable if that's an answer?

I think you should go with argon2id since it is what is considered "good" today, and since your program is new
https://pkg.go.dev/golang.org/x/crypto/argon2
This is a wrapper so it is safe as far as the Go crypto is concerned, and very easy to use:
https://github.com/alexedwards/argon2id

If you're wanting tokens you should probably use UUIDs

huangapple
  • 本文由 发表于 2022年7月1日 12:14:53
  • 转载请务必保留本文链接:https://go.coder-hub.com/72824306.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定