Модель угроз
- Цель подписи — доказать, что параметры платежа/уведомления сформированы доверенной стороной и не изменены по дороге.
- Злоумышленник обычно имеет доступ к URL платежа/параметрам в браузере и может перехватывать входящие уведомления (например, через логи, прокси, утечки в инфраструктуре).
- Критичный риск: возможность подделать оплату или “подтвердить” оплату, которой не было, если подпись можно вычислить без секрета.
SCI / подпись на MD5
В документации SCI описана подпись параметров платежной формы как MD5 от конкатенации полей (магазин/сумма/секрет/валюта/заказ), а также подпись уведомления (Result URL) как MD5 от (магазин/сумма/секрет2/заказ). Это прямо следует из официальных примеров и описаний подписи. Источник
Риск №2: подпись передаётся как параметр URL платежа (GET), что повышает шанс утечки через логи, историю браузера, referrer и сторонние системы мониторинга.
// Паттерн из документации (упрощённо):
sign = md5(merchant_id + ":" + amount + ":" + secret + ":" + currency + ":" + order_id)
webhook_sign = md5(merchant_id + ":" + amount + ":" + secret2 + ":" + order_id)
API v1 / HMAC-SHA256
В документации JSON API указано: “сортируем параметры по ключам, соединяем значения через ‘|’, затем считаем HMAC-SHA256 с использованием API-ключа” — пример приводится напрямую. Источник
// Пример паттерна из документации (PHP):
ksort(data)
signature = HMAC_SHA256( implode("|", data_values), api_key )
Слабое место реализации: если в качестве “api_key” фактически используется короткий ключ (например, 32-битное значение), представленный в виде hex-строки, то эффективная энтропия ключа остаётся низкой, несмотря на то что “строка выглядит длинной”.
- HMAC сам по себе не “добавляет” стойкости, если секрет слишком короткий.
- Опасный симптом: ключ выглядит как hex-строка фиксированной длины, но происхождение/генерация даёт слишком маленькое пространство перебора.
- Дополнительный риск: в подпись включаются только значения, без имён ключей — это усложняет защиту от некоторых классов коллизий представления (когда разные наборы полей дают одинаковую строку).
Рекомендации
- Для подписи запросов: использовать HMAC-SHA256/512 с криптографически случайным секретом достаточной длины (не “короткий int/32-bit”, не “пароль”).
- Для каноникализации: подписывать пары key=value, а не только значения, и однозначно определять кодировку/escape, чтобы исключить неоднозначности.
- Для webhook: проверять не только подпись, но и “свежесть” события (nonce/временная метка), защищаться от повтора, сверять сумму/валюту/ID заказа и статус.
- Для транспорта: избегать размещения подписи и чувствительных параметров в URL, где это возможно; контролировать логирование и referrer-политики.
- Для операционной безопасности: хранить секреты вне кода (env/secret storage), ротировать ключи и иметь процедуру отзыва.
Ссылки
- Документация FreeKassa: https://docs.freekassa.net/