Аутентификация и подпись запросов (HMAC)
В этом разделе описано, как выполнять аутентификацию запросов к HighHelp API с использованием алгоритма HMAC-SHA512 и как формировать цифровую подпись.
Регистрация в системе
Регистрацию выполняйте через личный кабинет мерчанта. Доступ в личный кабинет предоставляет специалист HighHelp.
При генерации ключей для кассы одновременно создаются:
-
пара RSA-ключей (публичный и приватный);
-
секретный HMAC-ключ.
Порядок действий:
-
Создайте кассу во вкладке Кассы.
-
Обратитесь к прикрепленному специалисту HighHelp для настройки кассы и проведения верификации.
-
После настройки и верификации кассы перейдите во вкладку API.
-
Найдите созданную кассу и нажмите кнопку Сгенерировать ключ.
-
В открывшемся окне проверьте название кассы и URL.
-
Нажмите и удерживайте кнопку Сгенерировать ключи.
-
Скопируйте и сохраните:
-
UUID— идентификатор кассы. Используется при взаимодействии с API и передается в заголовкеx-access-merchant-id; -
Private key(RSA) — приватный RSA-ключ в формате PEM. Используется для формирования цифровой подписи запросов; -
Public key(RSA) — публичный RSA-ключ. Используется для проверки подписи оповещений от HighHelp; -
Private key(HMAC) — секретный HMAC-ключ. Используется для формирования подписи запросов и оповещений при настроенном алгоритме HMAC-SHA512.Секретный HMAC-ключ доступен для скачивания только в момент генерации или обновления. После скачивания в разделе API → Настройки Callback отображается маскированное значение HMAC-ключа; повторное скачивание недоступно, доступно только обновление ключа.
Ключ выгружается в файл и не хранится на стороне HighHelp в открытом виде. На стороне HighHelp хранится только хеш и служебная информация, необходимая для проверки подписи.
-
-
Передайте значения
UUIDиPrivate key(HMAC) команде разработки или DevOps-специалисту и обеспечьте их защищенное хранение.
|
Не храните секретный HMAC-ключ в открытом виде в репозиториях, логах и системах мониторинга. Используйте специализированные хранилища секретов и ограничивайте доступ к нему по принципу наименьших привилегий. |
Генерация и обновление HMAC-ключа
При генерации ключей для кассы одновременно создаются HMAC-ключ и пара RSA-ключей. Если требуется сгенерировать HMAC-ключ отдельно или обновить существующий ключ, используйте инструкции ниже.
|
Секретный HMAC-ключ доступен для скачивания только в момент генерации или обновления. После скачивания в разделе API → Настройки Callback отображается маскированное значение ключа; повторное скачивание недоступно, доступно только обновление ключа. |
Генерация HMAC-ключа
Если для кассы не был сгенерирован HMAC-ключ при первоначальной настройке, выполните следующие действия:
-
Откройте личный кабинет мерчанта.
-
Перейдите в раздел API → Настройки Callback.
-
Нажмите на иконку + в блоке HMAC key.
-
Сохраните ключ в защищенном хранилище и передайте команде разработки.
Обновление HMAC-ключа
Если для кассы настроен алгоритм HMAC-SHA512 и требуется обновить только HMAC-ключ без обновления RSA-ключей, выполните следующие действия:
-
Откройте личный кабинет мерчанта.
-
Перейдите в раздел API → Настройки Callback.
-
Убедитесь, что текущий алгоритм подписи — HMAC (отображается внизу модального окна: Алгоритм: HMAC).
-
Нажмите на кнопку Обновить ключ в блоке HMAC key.
-
В открывшемся окне подтвердите операцию.
-
Сохраните новый секретный HMAC-ключ.
-
Обновите конфигурацию интеграции на стороне мерчанта, заменив старый HMAC-ключ на новый.
|
После обновления HMAC-ключа старый ключ перестанет работать немедленно. Убедитесь, что новый ключ корректно настроен на стороне мерчанта до начала использования. Рекомендуется выполнять обновление в период минимальной нагрузки на систему. |
Получение HMAC-ключа
Для проверки подписи оповещений используйте секретный HMAC-ключ, настроенный для кассы. Тот же ключ используется для формирования подписи запросов к API.
Секретный HMAC-ключ доступен для скачивания только в момент генерации или обновления. После скачивания в разделе API → Настройки Callback отображается маскированное значение ключа; повторное скачивание недоступно, доступно только обновление ключа.
Описание формата подписи оповещений и алгоритма проверки приведено в разделе Подпись оповещений (HMAC).
Смена алгоритма подписи с RSA на HMAC
Для смены алгоритма подписи с RSA на HMAC обратитесь к специалисту HighHelp. Смена алгоритма выполняется на стороне HighHelp после согласования.
Перед переключением убедитесь, что:
-
HMAC-ключ для кассы сгенерирован;
-
интеграция на стороне мерчанта готова к работе с HMAC-подписью;
-
обновлены скрипты для формирования подписи запросов и проверки подписи оповещений.
После смены алгоритма:
-
в личном кабинете доступен только HMAC-ключ настроенного для кассы алгоритма подписи;
-
в настройках оповещений отображается текущий алгоритм — HMAC (в нижней части модального окна: Алгоритм: HMAC);
-
все запросы и оповещения должны использовать HMAC-SHA512.
Аутентификация в API
Для HMAC-аутентификации запросов используйте следующие HTTP-заголовки:
-
x-access-timestamp -
x-access-merchant-id -
x-access-signature -
x-access-token -
x-access-merchant-algorithm
Алгоритм подписи (схематично):
x-access-merchant-algorithm = "HMAC-SHA512"
message = base64url(normalized_payload) + str(timestamp)
x-access-signature = base64url(HMAC_SHA512(secret_key, message))
Где:
-
normalized_payload— нормализованное представление JSON-тела запроса; -
timestamp— значение заголовкаx-access-timestampв виде строки; -
secret_key— секретный HMAC-ключ кассы (байтовый массив).
Если тело запроса отсутствует, используйте пустой объект {} и нормализуйте его как обычный JSON.
Заголовок x-access-timestamp
x-access-timestamp содержит время формирования запроса в формате Unix timestamp (количество секунд с 01.01.1970 00:00:00 UTC), указанное строкой.
Пример:
x-access-timestamp: 1716299720
|
Используйте время сервера, синхронизированное по NTP. Не используйте локальное время клиента браузера или мобильного приложения. |
Заголовок x-access-merchant-id
x-access-merchant-id содержит идентификатор кассы. Используйте значение UUID, полученное при генерации ключей для кассы.
В примерах кода идентификатор передается через переменную project_id.
Пример:
x-access-merchant-id: 57aff4db-b45d-42bf-bc5f-b7a499a01782
Заголовок x-access-merchant-algorithm
x-access-merchant-algorithm определяет алгоритм подписи, используемый для данного запроса.
Для HMAC используйте значение:
x-access-merchant-algorithm: HMAC-SHA512
|
Для HMAC-подписи всегда указывайте |
Заголовок x-access-token
x-access-token содержит маску секретного HMAC-ключа. Маска используется для идентификации ключа без раскрытия полного секрета.
Маску сформируйте по правилу:
<первые 3 символа ключа> + 7 астерисков (*) + <последние 3 символа ключа>
Пример функции формирования маски:
def masked_hmac(hmac_key: str) -> str:
return hmac_key[:3] + "*******" + hmac_key[-3:]
Пример значения заголовка:
x-access-token: abc*******xyz
|
Не передавайте полный секретный HMAC-ключ в заголовках, теле запроса или URL. Используйте только маску в |
Заголовок x-access-signature
x-access-signature содержит цифровую подпись запроса. Подпись формируется по алгоритму HMAC-SHA512.
Формат (схематично):
message = base64url(normalized_payload) + str(timestamp)
signature_bytes = HMAC_SHA512(secret_key, message)
x-access-signature = base64url(signature_bytes)
Порядок формирования подписи:
-
Нормализуйте тело запроса в строку
normalized_payloadс помощью алгоритма нормализации. -
Закодируйте строку
normalized_payloadв Base64Url, получите строкуencoded_payload. -
Сконкатенируйте
encoded_payloadиtimestamp(значение заголовкаx-access-timestamp), получите строкуmessage. -
Вычислите HMAC-SHA512 от
messageс использованием секретного HMAC-ключа. -
Закодируйте результат в Base64Url.
-
Передайте полученное значение в заголовке
x-access-signature.
Нормализация тела запроса
Для формирования подписи используется нормализованное представление JSON-тела запроса.
Алгоритм нормализации:
-
Выполните рекурсивный обход JSON-структуры (объекты и массивы).
-
Соберите пары в формате
путь:значение, где путь строится через двоеточие:-
для объектов:
parent:ключ; -
для массивов:
parent:индекс.
-
-
Преобразуйте булевы значения:
trueв1,falseв0. -
Используйте стандартное строковое представление чисел без локалей и разделителей (только цифры и, при необходимости, знак).
-
Отсортируйте все пары по алфавиту.
-
Склейте пары в одну строку, разделяя их символом
;.
Пример исходного JSON:
{
"amount": 100,
"status": "success",
"is_paid": true,
"data": {
"id": 123,
"is_active": false
}
}
Результат нормализации:
amount:100;data:id:123;data:is_active:0;is_paid:1;status:success
Пример функций нормализации на Python:
def parse_json(prefix, obj, result):
"""
Рекурсивный обход JSON-структуры для формирования пар путь:значение.
"""
if isinstance(obj, dict):
for key, value in obj.items():
if isinstance(key, bool):
key = int(key)
new_prefix = f"{prefix}:{key}" if prefix else str(key)
parse_json(new_prefix, value, result)
elif isinstance(obj, list):
for index, item in enumerate(obj):
if isinstance(item, bool):
item = int(item)
new_prefix = f"{prefix}:{index}"
parse_json(new_prefix, item, result)
else:
if isinstance(obj, bool):
obj = int(obj)
result.append(f"{prefix}:{obj}")
def normalize_message(payload: dict) -> str:
"""
Нормализация JSON в детерминированную строку (формат: путь:значение через ;).
"""
items: list[str] = []
parse_json("", payload, items)
items.sort()
return ";".join(items)
|
Если тело запроса отсутствует, используйте пустой объект |
Требования к нормализации
При реализации алгоритма нормализации учитывайте следующие требования:
-
Булевы значения: преобразуются в целочисленное представление (
true→1,false→0). -
Значения null: преобразуются в строку
None. Не используйте пустые строки или пробелы. -
Числа: используйте стандартное строковое представление без локализации (разделителей групп разрядов, локальных форматов). Не добавляйте незначащие нули.
-
Массивы: порядок элементов сохраняется в исходной последовательности. Индексы элементов добавляются к пути как
:0,:1,:2, … -
Объекты: после формирования всех пар
путь:значениевыполняется сортировка по алфавиту по полной строке. -
Кодировка символов: используйте UTF-8 для кодирования перед применением Base64Url. Не изменяйте регистр символов.
-
Пробелы и форматирование: не добавляйте и не удаляйте пробелы в значениях. Используйте точные значения из JSON-структуры.
Алгоритм формирования подписи
-
Сформируйте объект
payloadс телом запроса. -
Нормализуйте
payloadфункциейnormalize_message():joined_result = normalize_message(payload) -
Закодируйте нормализованную строку в Base64Url и добавьте метку времени:
timestamp = int(time.time()) message = "{}{}".format( base64.urlsafe_b64encode(joined_result.encode()).decode("utf-8"), str(timestamp), ) -
Вычислите HMAC-SHA512 от строки
messageс использованием секретного HMAC-ключа. -
Закодируйте результат в Base64Url.
-
Передайте полученное значение в заголовке
x-access-signature.
Пример запроса с подписью (Python3)
Ниже приведен пример формирования подписи HMAC-SHA512 и отправки запроса к API.
import base64
import json
import time
import hmac
import hashlib
import requests
url = "https://api.hh-processing.com/api/v1/payment/p2p/payin"
# Идентификатор кассы (UUID)
project_id = "57aff4db-b45d-42bf-bc5f-b7a499a01782"
# Секретный HMAC-ключ (байты)
secret_key = b"<YOUR-HMAC-SECRET-KEY-BYTES>"
payload = {
"general": {
"project_id": project_id
}
}
def parse_json(prefix, obj, result):
if isinstance(obj, dict):
for key, value in obj.items():
if isinstance(key, bool):
key = int(key)
new_prefix = f"{prefix}:{key}" if prefix else str(key)
parse_json(new_prefix, value, result)
elif isinstance(obj, list):
for index, item in enumerate(obj):
if isinstance(item, bool):
item = int(item)
new_prefix = f"{prefix}:{index}"
parse_json(new_prefix, item, result)
else:
if isinstance(obj, bool):
obj = int(obj)
result.append(f"{prefix}:{obj}")
def normalize_message(data: dict) -> str:
items = []
parse_json("", data, items)
items.sort()
return ";".join(items)
def masked_hmac(hmac_key: str) -> str:
"""
Маскирование HMAC-ключа для безопасного логирования.
"""
return hmac_key[:3] + "*******" + hmac_key[-3:]
# Нормализация тела запроса
normalized = normalize_message(payload)
# Кодирование в Base64Url
encoded = base64.urlsafe_b64encode(normalized.encode("utf-8")).decode("utf-8")
# Метка времени Unix (секунды)
timestamp = int(time.time())
# Формирование сообщения для подписи
message = f"{encoded}{timestamp}".encode("utf-8")
# Вычисление HMAC-SHA512
signature_bytes = hmac.new(secret_key, message, hashlib.sha512).digest()
signature_b64url = base64.urlsafe_b64encode(signature_bytes).decode("utf-8")
# Маска HMAC-ключа для x-access-token
hmac_mask = masked_hmac(secret_key.decode("utf-8"))
# Формирование заголовков
headers = {
"content-type": "application/json",
"x-access-merchant-id": project_id,
"x-access-timestamp": str(timestamp),
"x-access-signature": signature_b64url,
"x-access-merchant-algorithm": "HMAC-SHA512",
"x-access-token": hmac_mask,
}
# Сериализация тела запроса (JSON)
dumped = json.dumps(payload, separators=(",", ":")) if payload else "{}"
response = requests.post(url, headers=headers, data=dumped)
print(response.status_code)
Рекомендации по безопасности
-
Храните секретный HMAC-ключ на стороне сервера.
-
Обновляйте ключи по запросу через специалиста HighHelp.
-
Не передавайте ключи по незащищенным каналам.
-
Не логируйте ключ полностью. Маскируйте значение: первые 3 символа + 7 астерисков (
*) + последние 3 символа.Пример маскирования ключа
def masked_hmac_key(key: str) -> str: return key[:3] + "*******" + key[-3:]
Форма для проверки подписи
Используйте форму ниже для проверки корректности формирования подписи HMAC-SHA512 для запросов к API HighHelp.
|
Обработка введенных данных выполняется локально в браузере; данные не передаются на сервер. |
Выполнение проверки
-
Вставьте JSON-тело запроса в первое поле.
-
Введите ваш секретный ключ.
-
Укажите временную метку в формате Unix timestamp.
-
Вставьте подпись, которую необходимо проверить.
-
Нажмите кнопку Проверить подпись.
Форма отобразит пошаговый процесс формирования подписи и результат проверки предоставленной подписи.
Пример тестовых данных
Для проверки подписи можно использовать следующие тестовые данные:
JSON-тело запроса:
{"general":{"project_id":"test-project-123"},"payment":{"amount":100000,"currency":"USD"}}
Секретный ключ: test-secret-key
Timestamp: 1716299720
После нажатия на кнопку Проверить подпись форма отобразит:
-
Нормализованное представление данных.
-
Используемую временную метку.
-
Вычисленную подпись.
-
Результат проверки предоставленной подписи.