SSO를 위한 Secret + Payload 해싱

payload를 파싱한 결과 기본적으로 base64 형식인 것 같지만, base64 인코딩된 payload의 256SHA 해시가 올바르지 않습니다. OG 게시글의 예시 secret과 URL을 사용하고 있습니다.

다음 코드에서 다음 출력이 나옵니다:

 payloadURL = bm9uY2U9Y2I2ODI1MWVlZmI1MjExZTU4YzAwZmYxMzk1ZjBjMGI=

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

제 코드:

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

	// URL 쿼리에서 payload와 sig를 가져옵니다
	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)

	// base64 버전에서 raw payload를 가져옵니다
	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는 hex 인코딩되어 있으므로, 비교할 수 있도록 해시된 payload를 hex 인코딩합니다.
	//hashAsString := hex.EncodeToString(hash.Sum(nil))

	// payload의 hex 인코딩된 해시를 hex 인코딩된 sig와 비교합니다
	if strings.Compare(payload256, sig) != 0 {
		log.Fatal(err)
	}

업데이트: 결과로 생성된 HMAC-SHA256 해시를 hex로 인코딩한 후 이 문제를 수정했습니다. (서명도 hex 인코딩되어 있습니다. 또한 SSO 가이드의 예시가 올바르지 않다는 내용을 언급한 이 게시글도 참고하세요.) 따라서 이 코드를 변경했습니다:

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