# Хеширование секрета и полезной нагрузки для SSO

**URL:** https://meta.discourse.org/t/hashing-secret-payload-for-sso/169284
**Category:** SSO
**Created:** [04.Ноябрь.2020 22:01:14 UTC](https://meta.discourse.org/t/hashing-secret-payload-for-sso/169284 "2020-11-04T22:01:14Z")
**Posts on this page:** 10
**Page:** 1

<div class="post-metadata">

### Author: ![nategoethel](https://avatars.discourse-cdn.com/v4/letter/n/90ced4/32.png) [@nategoethel](https://meta.discourse.org/u/nategoethel)
#### Post date: [04.Ноябрь.2020 22:01:14 UTC](https://meta.discourse.org/t/hashing-secret-payload-for-sso/169284/1 "2020-11-04T22:01:14Z")

</div>

Я пытаюсь следовать [официальному руководству по SSO](https://meta.discourse.org/t/official-single-sign-on-for-discourse-sso/13045). На своём сервере я использую Golang и пытаюсь сопоставить HMAC-SHA256-хэш от `payload` + `secret` с `sig`, но получаю разные значения. Как вы выполняете хеширование? Разбиваете ли вы payload на исходное, не подписанное содержимое и снова хешируете его?

---

<div class="post-metadata">

### Author: ![michaeld](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/michaeld/32/1594_2.png) [@michaeld](https://meta.discourse.org/u/michaeld)
#### Post date: [04.Ноябрь.2020 22:07:47 UTC](https://meta.discourse.org/t/hashing-secret-payload-for-sso/169284/2 "2020-11-04T22:07:47Z")

</div>

Как выглядит ваш код?

Вы закодировали полезную нагрузку в base64?

И правильно ли вы указали порядок параметров? В разных языках и библиотеках порядок параметров разный: (ключ, сообщение) или (сообщение, ключ). Именно это каждый раз сбивает меня с толку.

---

<div class="post-metadata">

### Author: ![nategoethel](https://avatars.discourse-cdn.com/v4/letter/n/90ced4/32.png) [@nategoethel](https://meta.discourse.org/u/nategoethel)
#### Post date: [04.Ноябрь.2020 22:17:09 UTC](https://meta.discourse.org/t/hashing-secret-payload-for-sso/169284/3 "2020-11-04T22:17:09Z")

</div>

После разбора `payload` выяснилось, что по умолчанию он в формате base64, но хеш 256SHA от закодированного в base64 payload неверен. Я использую секрет и 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"

	// извлекаем payload и sig из параметров 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)

	// получаем исходный payload из 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 закодирован в шестнадцатеричный формат, поэтому также закодируем хешированный payload в hex для сравнения.
	//hashAsString := hex.EncodeToString(hash.Sum(nil))

	// сравниваем hex-закодированный хеш payload с hex-закодированным sig
	if strings.Compare(payload256, sig) != 0 {
		log.Fatal(err)
	}

```

Обновление: я исправил это, закодировав полученный хеш HMAC-SHA256 в hex (подпись также закодирована в hex). Также см. [этот пост](https://meta.discourse.org/t/hmac-256-example-on-official-sso-page/92546/2), где указано, что примеры в руководстве по 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)
}

```

---

<div class="post-metadata">

### Author: ![michaeld](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/michaeld/32/1594_2.png) [@michaeld](https://meta.discourse.org/u/michaeld)
#### Post date: [04.Ноябрь.2020 22:20:15 UTC](https://meta.discourse.org/t/hashing-secret-payload-for-sso/169284/4 "2020-11-04T22:20:15Z")

</div>

> [@nategoethel](#):
>
> `if strings.Compare(payload256, sig)`

Откуда берется `payload256`?

---

<div class="post-metadata">

### Author: ![nategoethel](https://avatars.discourse-cdn.com/v4/letter/n/90ced4/32.png) [@nategoethel](https://meta.discourse.org/u/nategoethel)
#### Post date: [04.Ноябрь.2020 22:26:54 UTC](https://meta.discourse.org/t/hashing-secret-payload-for-sso/169284/6 "2020-11-04T22:26:54Z")

</div>

Извините, я обновил первый пост с более чистым кодом.

---

<div class="post-metadata">

### Author: ![michaeld](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/michaeld/32/1594_2.png) [@michaeld](https://meta.discourse.org/u/michaeld)
#### Post date: [05.Ноябрь.2020 05:58:20 UTC](https://meta.discourse.org/t/hashing-secret-payload-for-sso/169284/8 "2020-11-05T05:58:20Z")

</div>

> [@nategoethel](#):
>
> `bm9uY2U9Y2I2ODI1MWVlZmI1MjExZTU4YzAwZmYxMzk1ZjBjMGI%3D%0A&sig=`

Что делает там этот `%0A` прямо перед `&sig`? Это URL-кодированный перевод строки… именно поэтому в вашем выводе отладки после печати payloadURL появляется пустая строка — он всё ещё прицеплен в конце.

---

<div class="post-metadata">

### Author: ![nategoethel](https://avatars.discourse-cdn.com/v4/letter/n/90ced4/32.png) [@nategoethel](https://meta.discourse.org/u/nategoethel)
#### Post date: [05.Ноябрь.2020 15:40:43 UTC](https://meta.discourse.org/t/hashing-secret-payload-for-sso/169284/9 "2020-11-05T15:40:43Z")

</div>

Отличное замечание! Я исправил это здесь, добавив символ новой строки в параметры .Trim():

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

Теперь мой вывод выглядит так:

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

```

---

<div class="post-metadata">

### Author: ![michaeld](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/michaeld/32/1594_2.png) [@michaeld](https://meta.discourse.org/u/michaeld)
#### Post date: [05.Ноябрь.2020 15:52:22 UTC](https://meta.discourse.org/t/hashing-secret-payload-for-sso/169284/10 "2020-11-05T15:52:22Z")

</div>

Вам стоит проверить, откуда именно берётся перенос строки, и предотвратить его добавление.

Кроме того, в полезной нагрузке должно быть больше пар name=value, чем просто nonce?

---

<div class="post-metadata">

### Author: ![nategoethel](https://avatars.discourse-cdn.com/v4/letter/n/90ced4/32.png) [@nategoethel](https://meta.discourse.org/u/nategoethel)
#### Post date: [05.Ноябрь.2020 15:54:31 UTC](https://meta.discourse.org/t/hashing-secret-payload-for-sso/169284/11 "2020-11-05T15:54:31Z")

</div>

Это просто пример из руководства по SSO для Discourse, поэтому я не могу сказать, откуда взялся перенос строки. Судя по всему, в руководстве есть ошибка (согласно [этому сообщению](https://meta.discourse.org/t/hmac-256-example-on-official-sso-page/92546/2)), и похоже, что в примере произошла ошибка копирования/вставки.

---

<div class="post-metadata">

### Author: ![michaeld](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/michaeld/32/1594_2.png) [@michaeld](https://meta.discourse.org/u/michaeld)
#### Post date: [06.Ноябрь.2020 05:57:35 UTC](https://meta.discourse.org/t/hashing-secret-payload-for-sso/169284/12 "2020-11-06T05:57:35Z")

</div>

Возможно, вы слишком много копируете из разных версий.

Но, глядя на ваш пост прямо над этим, payloadURL не закодирован в URL, а payload256 закодирован не в шестнадцатеричном формате, а в base64.

Может быть, вы могли бы снова опубликовать ваш текущий код и текущий вывод.
