Hachage du secret + charge utile pour SSO

J’essaie de suivre le guide officiel SSO. J’utilise Golang sur mon serveur et je tente de faire correspondre le hachage HMAC-SHA256 du payload + secret au sig, mais j’obtiens des valeurs différentes. Comment effectuez-vous ce hachage ? Décomposez-vous le payload en contenu brut non signé avant de le re-hacher ?

À quoi ressemble votre code ?

Avez-vous encodé la charge utile en base64 ?

Et avez-vous respecté l’ordre des paramètres ? Différents langages ou bibliothèques ont des ordres de paramètres différents (clé, message) ou (message, clé). C’est ce qui me trompe à chaque fois.

1 « J'aime »

Après avoir analysé le payload, il semble qu’il soit en base64 par défaut, mais le hachage SHA256 du payload encodé en base64 n’est pas correct. J’utilise le secret et l’URL d’exemple du post original.

Le code suivant me donne la sortie suivante :

 payloadURL = bm9uY2U9Y2I2ODI1MWVlZmI1MjExZTU4YzAwZmYxMzk1ZjBjMGI=

sig = 2828aa29899722b35a2f191d34ef9b3ce695e0e6eeec47deb46d588d70c7cb56
payloadRaw = nonce=cb68251eefb5211e58c00ff1395f0c0b
payload256 = KCiqKYmXIrNaLxkdNO+bPOaV4Obu7EfetG1YjXDHy1Y=

Mon code :

testURL := "http://www.example.com/discourse/sso?sso=bm9uY2U9Y2I2ODI1MWVlZmI1MjExZTU4YzAwZmYxMzk1ZjBjMGI%3D%0A&sig=2828aa29899722b35a2f191d34ef9b3ce695e0e6eeec47deb46d588d70c7cb56"	
	ssoSecret := "d836444a9e4084d5b224a60c208dce14"

	// récupérer le payload et la signature depuis la requête URL
	u, err := url.Parse(testURL)
	if err != nil {
		log.Fatal(err)
	}

	q := u.Query()
	payloadURL := strings.Trim(fmt.Sprint(q["sso"]), "=[]")
	sig := strings.Trim(fmt.Sprint(q["sig"]), "[]")
	
	fmt.Printf("payloadURL = %s\n", payloadURL)
	fmt.Printf("sig = %s\n", sig)

	// obtenir le payload brut à partir de la version base64
	payloadRaw, err := base64.StdEncoding.DecodeString(payloadURL)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("payloadRaw = %s\n", payloadRaw)
	
	key := []byte(ssoSecret)
	message := []byte(payloadURL)
	hash := hmac.New(sha256.New, key)
	hash.Write(message)
	payload256 := base64.StdEncoding.EncodeToString(hash.Sum(nil))
	if err != nil {
		log.Fatal(err)
	}
	
	fmt.Printf("payload256 = %s\n", payload256)

	// la signature est encodée en hexadécimal, donc encodons également le hachage du payload en hex pour pouvoir comparer.
	//hashAsString := hex.EncodeToString(hash.Sum(nil))

	// comparer le hachage hexadécimal du payload avec la signature encodée en hex
	if strings.Compare(payload256, sig) != 0 {
		log.Fatal(err)
	}

Mise à jour : J’ai résolu ce problème après avoir encodé en hexadécimal mon hachage HMAC-SHA256 résultant (la signature est également encodée en hexadécimal). Voir également ce post qui indique que les exemples dans le guide SSO sont incorrects. J’ai donc modifié ce code :

key := []byte(ssoSecret)
message := []byte(payloadURL)
hash := hmac.New(sha256.New, key)
hash.Write(message)
payload256 := hex.EncodeToString(hash.Sum(nil))
if err != nil {
	log.Fatal(err)
}

D’où vient payload256 ?

Désolé, j’ai mis à jour le premier message avec un code plus propre.

Que fait ce %0A juste avant &sig ? C’est un saut de ligne encodé en URL… c’est pourquoi il y a une ligne vide dans votre sortie de débogage après avoir affiché payloadURL, il est toujours collé à la fin.

1 « J'aime »

Bonne remarque ! Je l’ai corrigé ici en ajoutant le caractère de nouvelle ligne aux paramètres de .Trim() :

payloadURL := strings.Trim(fmt.Sprint(q["sso"]), "[]\n")

Mon résultat est donc maintenant :

payloadURL = bm9uY2U9Y2I2ODI1MWVlZmI1MjExZTU4YzAwZmYxMzk1ZjBjMGI=
sig = 2828aa29899722b35a2f191d34ef9b3ce695e0e6eeec47deb46d588d70c7cb56
payloadRaw = nonce=cb68251eefb5211e58c00ff1395f0c0b
payload256 = HOFJT5RIS29qCSvpsVzMHNr7H4Rgo4OPuw4Ig8Q5BHE=

Vous devriez examiner d’où provient réellement le saut de ligne et éviter qu’il soit ajouté.

De plus, la charge utile devrait contenir plus de paires nom=valeur que le seul nonce ?

1 « J'aime »

Ceci n’est que l’exemple tiré du guide SSO de Discourse, je ne peux donc pas dire d’où vient la nouvelle ligne. Apparemment, le guide est erroné (selon ce post), et il semble qu’il y ait eu une erreur de copier-coller dans l’exemple.

Peut-être y a-t-il un peu trop de copier-coller entre différentes versions.

Mais en regardant votre message juste au-dessus de celui-ci, votre payloadURL n’est pas encodé en URL et payload256 n’est pas encodé en hexadécimal mais en base64.

Peut-être pouvez-vous republier votre code actuel et votre sortie actuelle.

1 « J'aime »