Hashing del segreto + payload per SSO

Sto cercando di seguire la guida ufficiale SSO. Sto utilizzando Golang sul mio server e sto cercando di far corrispondere l’hash HMAC-SHA256 del payload + secret alla sig, ma ottengo valori diversi. Come state eseguendo l’hashing? State scomponendo il payload nel contenuto grezzo non firmato e lo state ricalcolando?

Com’è fatto il tuo codice?

Hai codificato il payload in base64?

E hai rispettato l’ordine corretto dei parametri? Linguaggi e librerie diversi hanno ordini diversi (chiave, messaggio) o (messaggio, chiave). È quello che mi frega ogni volta.

Dopo aver analizzato il payload, sembra che di default sia in base64, ma l’hash 256SHA del payload codificato in base64 non è corretto. Sto usando il segreto e l’URL di esempio dal post originale.

Il seguente codice mi restituisce questo output:

 payloadURL = bm9uY2U9Y2I2ODI1MWVlZmI1MjExZTU4YzAwZmYxMzk1ZjBjMGI=

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

Il mio codice:

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

	// estrai payload e sig dalla query dell'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)

	// ottieni il payload grezzo dalla versione 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)

	// sig è codificato in esadecimale, quindi codifica in esadecimale anche l'hash del payload per poter confrontare.
	//hashAsString := hex.EncodeToString(hash.Sum(nil))

	// confronta l'hash in esadecimale del payload con il sig in esadecimale
	if strings.Compare(payload256, sig) != 0 {
		log.Fatal(err)
	}

Aggiornamento: ho risolto dopo aver codificato in esadecimale il mio hash HMAC-SHA256 risultante (anche la firma è codificata in esadecimale. Vedi anche questo post che afferma che gli esempi nella guida SSO sono errati. Quindi ho modificato questo codice:

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

Da dove proviene payload256?

Scusa, ho aggiornato il primo post con un codice più pulito.

Cosa sta facendo quel %0A proprio prima di &sig? È un ritorno a capo codificato in URL… ecco perché c’è una riga vuota nella tua output di debug dopo aver stampato payloadURL, è ancora attaccata alla fine.

Ottimo riscontro! L’ho corretto qui aggiungendo il carattere di nuova riga ai parametri di .Trim():

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

Quindi ora il mio output è:

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

Dovresti controllare da dove proviene effettivamente la nuova riga ed evitare che venga aggiunta.

Inoltre, il payload dovrebbe contenere più coppie nome=valore rispetto al solo nonce?

Questi sono solo gli esempi tratti dalla guida SSO di Discourse, quindi non riesco a capire da dove provenga la nuova riga. A quanto pare la guida è errata (secondo questo post), e sembra esserci stato un errore di copia/incolla nell’esempio.

Forse c’è un po’ troppo copia-incolla tra diverse versioni.

Ma guardando il tuo post appena sopra questo, il tuo payloadURL non è codificato in URL e payload256 non è codificato in esadecimale ma in base64.

Forse puoi ripostare il tuo codice attuale e la tua output attuale.