Discourse をアカウントプロバイダーとして使用し、PBKDF2 の問題

こんにちは。おそらく愚かな質問かもしれませんが、フォーラムを XenForo から Discourse に移行しています。認証用のバックエンドサーバーがあり、データベースに接続してユーザーテーブルに対して資格情報を検証する必要があります。

XenForo の bcrypt アルゴリズムは期待どおりに、手間なく機能しました。しかし、Discourse に移行したところ、PBKDF2 アルゴリズムが私の期待どおりに動作しないようです。まったく同じパスワード、まったく同じソルト、まったく同じ反復回数と長さであるにもかかわらず、出力ハッシュが異なります。

PBKDF2 アルゴリズムのさまざまな実装を試しましたが、すべて同じ (Discourse のものとは異なる) ハッシュを出力しました。独自の С++ 実装も含まれています。
OAuth2 や SSO のようなメカニズムは、追加のオーバーヘッドとそれに伴う追加作業のため、避けたいと考えています。

このようなユースケースで Discourse を使用したことがある方、または使用したことがある方は、この問題をどのように解決しましたか?

migrate password プラグインを使用していますか?

いいえ、少なくとも私が知る限りではありません。これについて話していますか?

「いいね!」 1

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バインディングがあるもの)に切り替える必要があります。

短いテストケースの例はありますか?

例えば、上記の情報を利用した場合、何が得られますか?

「いいね!」 1

申し訳ありませんが、タイムゾーンが面倒なので、現時点でお伝えすることはできません。こちらはもう遅いので、翌日にならないとできません。

ご依頼の通りに実行しました。パスワードは 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

気にする必要はありません。投稿で行っていたデコードされたソルトではなく、ソルトの16進数表現を引数として使用する必要がありました。これでハッシュは等しくなりました。

「いいね!」 5

私もそれが理論でした!最初、私は同じ間違いをしました。

「いいね!」 1

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.