您好。这可能是一个愚蠢的问题,但我们正在将论坛从 XenForo 迁移到 Discourse。我们有一个用于授权的后端服务器,该服务器涉及连接到数据库并将凭据与 users 表进行验证。
XenForo 的 bcrypt 算法按预期工作,没有任何麻烦。然而,当我们迁移到 Discourse 时,PBKDF2 算法似乎不符合我的预期。相同的密码、相同的盐、相同的迭代次数和长度,但输出的哈希值却不同。
我尝试了 PBKDF2 算法的各种不同实现,但它们都输出了完全相同的(与 Discourse 不同的)哈希值。包括我自己的实现。
我宁愿避免使用 OAuth2 或 SSO 等机制,因为它们会增加额外的开销和工作量。
有人将 Discourse 用于此类用例吗?如果有,您是如何解决这个问题的?
pfaffman
(Jay Pfaffman)
2
您在使用 migrate password 插件吗?
你尝试过openssl的实现吗?那正是我们使用的(你可以在discourse/lib/pbkdf2.rb中看到)。
例如,在将用户的密码设置为swordfish#后:
discourse_development=# select password_hash, salt, password_algorithm from users where id=2;
-[ RECORD 1 ]------+-----------------------------------------------------------------
password_hash | 67650523776bdc87ebcd2fc11719553c87b11e6c4da49806d9d5232460d2adc9
salt | 712ef44dd6fe6d6f0f1b6f702bb78459
password_algorithm | $pbkdf2-sha256$i=600000,l=32$
$ openssl kdf \
-kdfopt pass:'swordfish#' \
-kdfopt salt:712ef44dd6fe6d6f0f1b6f702bb78459 \
-kdfopt digest:SHA2-256 \
-kdfopt iter:600000 \
-keylen 32 \
PBKDF2 \
| tr -d : | tr '[:upper:]' '[:lower:]'
67650523776bdc87ebcd2fc11719553c87b11e6c4da49806d9d5232460d2adc9
1 个赞
我们主要为 Xenforo 使用了 Go 的 crypto/bcrypt 实现。来自各种 pbkdf2 算法实现的相同哈希值表明 Go 可能以某种不同的方式存储字符串或将字符串转换为字节。
我明天得试试(这里已经很晚了)。如果 OpenSSL 能给我想要的结果,那么我将不得不为 Go 寻找 OpenSSL 绑定,或者我将不得不切换到一种完全不同的语言(具有 OpenSSL 绑定)来作为后端。
抱歉,由于时区问题,我现在无法告知您。这里已经很晚了,我只能明天再告诉您。
我已按您的要求操作。密码是 swordfish#98765。
数据库条目:
discourse=> SELECT password_hash, salt, password_algorithm FROM users WHERE id=1;
password_hash | salt | password_algorithm
------------------------------------------------------------------+----------------------------------+-------------------------------
db3f0829e66336323e81110a1792a76000b9c60605e1fa6964797ea1b07c33c6 | 0d079078e220158011afaf497794166d | $pbkdf2-sha256$i=600000,l=32$
(1 row)
OpenSSL:
/var/discourse# openssl kdf \
> -kdfopt pass:'swordfish#98765' \
> -kdfopt salt:0d079078e220158011afaf497794166d \
> -kdfopt digest:SHA2-256 \
> -kdfopt iter:600000 \
> -keylen 32 \
> PBKDF2 \
> | tr -d : | tr '[:upper:]' '[:lower:]'
db3f0829e66336323e81110a1792a76000b9c60605e1fa6964797ea1b07c33c6
Go 代码:
var userId int
var hash string
var salt string
var active bool
row := s.Database.QueryRow(`
SELECT u.id, u.password_hash, u.salt, u.active
FROM users AS u
INNER JOIN user_emails AS ue ON u.id = ue.user_id
WHERE ue.email = $1;`,
email,
)
if err := row.Scan(&userId, &hash, &salt, &active); err != nil {
// error handling...
}
hashBytes, err := hex.DecodeString(hash)
if err != nil {
// error handling...
}
saltBytes, err := hex.DecodeString(salt)
if err != nil {
// error handling...
}
key := pbkdf2.Key([]byte(password), saltBytes, 600000, 32, sha256.New)
fmt.Printf("salt: %v\n", salt)
fmt.Printf("hash: %v\n", hash)
fmt.Printf("hex.EncodeToString(key): %v\n", hex.EncodeToString(key))
上述代码的输出:
salt: 0d079078e220158011afaf497794166d
hash: db3f0829e66336323e81110a1792a76000b9c60605e1fa6964797ea1b07c33c6
hex.EncodeToString(key): b378c12d96ac62a6099fc674d334f0793e6294f7927da0badc811e794a960802
算了。我必须使用盐的十六进制表示形式作为参数,而不是像我在上面的帖子中所做的那样使用解码后的盐。现在哈希值相等了。
5 个赞
system
(system)
关闭
11
This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.