Utilisation de Discourse comme fournisseur de compte et problèmes PBKDF2

Salut. C’est probablement une question stupide, mais nous avons migré notre forum de XenForo vers Discourse. Nous avons un serveur backend pour l’autorisation qui implique de se connecter à la base de données et de vérifier les informations d’identification par rapport à la table des utilisateurs.

L’algorithme bcrypt de XenForo a fonctionné comme prévu, et sans aucun problème. Cependant, lorsque nous avons migré vers Discourse, l’algorithme PBKDF2 ne semble pas avoir répondu à mes attentes. Même mot de passe exact, même sel exact, même nombre d’itérations et même longueur exacts, mais le hachage de sortie est différent.

J’ai essayé diverses implémentations de l’algorithme PBKDF2, mais elles produisent toutes le même hachage (différent de celui de Discourse). Y compris ma propre implémentation.
Je préférerais éviter les mécanismes comme OAuth2 ou SSO en raison de la surcharge supplémentaire et du travail supplémentaire qu’ils nous imposent.

Quelqu’un a-t-il utilisé Discourse pour de tels cas d’utilisation, et si oui, comment avez-vous résolu ce problème ?

Utilisez-vous le plugin migrate password ?

Non, du moins pas à ma connaissance. Parlez-vous de ceci ?

1 « J'aime »

Avez-vous essayé l’implémentation de openssl ? C’est ce que nous utilisons (vous pouvez la voir dans discourse/lib/pbkdf2.rb).

À titre d’exemple, après avoir défini le mot de passe d’un utilisateur à 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 « J'aime »

Nous avons principalement utilisé l’implémentation crypto/bcrypt de Go pour Xenforo. Les mêmes hachages provenant de diverses implémentations d’algorithmes pbkdf2 me suggèrent que Go stocke peut-être les chaînes ou convertit les chaînes en octets d’une manière quelque peu différente.

Je devrai essayer cela demain (il est tard ici). Si OpenSSL me donne le résultat souhaité, alors je devrai chercher des liaisons OpenSSL pour Go, ou je devrai passer à un langage entièrement différent (qui a des liaisons OpenSSL) pour le backend.

Avez-vous un exemple de cas de test court ?

Par exemple, si vous utilisez les informations ci-dessus, qu’obtenez-vous ?

1 « J'aime »

Désolé, je ne suis pas en mesure de vous le dire actuellement car les fuseaux horaires sont ennuyeux. Il est très tard ici et je ne pourrai le faire que le lendemain.

J’ai fait ce que vous avez demandé. Le mot de passe est swordfish#98765.

Entrée de la base de données :

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

Code 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 {
	// gestion des erreurs...
}

hashBytes, err := hex.DecodeString(hash)
if err != nil {
	// gestion des erreurs...
}

saltBytes, err := hex.DecodeString(salt)
if err != nil {
	// gestion des erreurs...
}

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))

Sortie du code ci-dessus :

salt: 0d079078e220158011afaf497794166d
hash: db3f0829e66336323e81110a1792a76000b9c60605e1fa6964797ea1b07c33c6
hex.EncodeToString(key): b378c12d96ac62a6099fc674d334f0793e6294f7927da0badc811e794a960802

Laissez tomber. J’ai dû utiliser la représentation hexadécimale du sel comme argument, et non le sel décodé comme je le faisais dans le message ci-dessus. Maintenant, les hachages sont égaux.

5 « J'aime »

C’était aussi ma théorie ! J’ai fait la même erreur au début.

1 « J'aime »

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