При интеграции 1С с внешними веб-сервисами, торговыми площадками и биржами часто используется механизм аутентификации на основе подписи запроса алгоритмом HMAC-SHA512. В процессе отправки запроса сервер может возвращать ошибку проверки подписи (например, {"success":0,"error":"invalid sign"}). Проанализируем причины возникновения этой проблемы и разберем по шагам, как правильно подготовить тело запроса, рассчитать хэш и настроить заголовки.
Выясним причину, по которой сервер отклоняет сформированную подпись. Чаще всего сбой происходит из-за следующих факторов:
application/x-www-form-urlencoded).HTTPЗапрос.УстановитьТелоИзСтроки при кодировании в UTF-8 может добавлять символы BOM (EF BB BF) в начало тела. Сервер считывает эти байты, из-за чего хэш тела не совпадает с подписью в заголовке.nonce: значение счетчика или метки времени должно строго увеличиваться с каждым последующим запросом.Рассмотрим подробнее реализацию функции шифрования на платформе Windows с использованием стандартных COM-объектов .NET Framework (System.Security.Cryptography.HMACSHA512 и System.Text.UTF8Encoding).
&НаСервере
Функция ЗашифроватьHMACSHA512(Знач СтрокаДанных, Знач СекретныйКлюч)
Текст = Новый COMОбъект("System.Text.UTF8Encoding");
Криптография = Новый COMОбъект("System.Security.Cryptography.HMACSHA512");
// Передаем байты секретного ключа
Криптография.Key = Текст.GetBytes_4(СекретныйКлюч);
// Вычисляем хэш от переданной строки данных
БайтыДанных = Текст.GetBytes_4(СтрокаДанных);
ХешБайт = Криптография.ComputeHash_2(БайтыДанных).Выгрузить();
// Преобразуем массив байтов в шестнадцатеричную строку (в нижнем регистре)
StringBuilder = Новый COMОбъект("System.Text.StringBuilder");
Для Каждого Байт Из ХешБайт Цикл
StringBuilder.AppendFormat("{0:x2}", Байт);
КонецЦикла;
Возврат StringBuilder.ToString();
КонецФункции
Посмотрим на пример правильного формирования параметров и заголовков при отправке POST-запроса через объекты HTTPСоединение и HTTPЗапрос.
&НаСервере
Процедура ВыполнитьЗапросКАПИ()
КлючАпи = "ваш_api_key";
Секрет = "ваш_secret_key";
// Формируем уникальное значение nonce (например, на основе текущего времени)
ТекущийNonce = Формат(ТекущаяУниверсальнаяДатаВМиллисекундах(), "ЧГ=0");
// Формируем строку параметров тела POST-запроса
// Если API требует apiKey в теле запроса, обязательно добавляем его
ТелоПараметры = "method=getInfo&nonce=" + ТекущийNonce + "&apikey=" + КлючАпи;
// Вычисляем подпись HMAC-SHA512 от строки параметров
Подпись = ЗашифроватьHMACSHA512(ТелоПараметры, Секрет);
// Инициализируем защищенное HTTPS-соединение
SSLСоединение = Новый ЗащищенноеСоединениеOpenSSL(Неопределено, Неопределено);
Соединение = Новый HTTPСоединение("api.example.com",,,,, 30, SSLСоединение);
HTTPЗапрос = Новый HTTPЗапрос("/tapi");
HTTPЗапрос.Заголовки.Вставить("Key", КлючАпи);
HTTPЗапрос.Заголовки.Вставить("Sign", Подпись);
HTTPЗапрос.Заголовки.Вставить("Content-Type", "application/x-www-form-urlencoded");
// Отключаем добавление BOM-маркера в начало тела
HTTPЗапрос.УстановитьТелоИзСтроки(ТелоПараметры, КодировкаТекста.UTF8, ИспользованиеByteOrderMark.НеИспользовать);
// Отправка запроса на сервер
Ответ = Соединение.ОтправитьДляОбработки(HTTPЗапрос);
СтрокаОтвета = Ответ.ПолучитьТелоКакСтроку();
// Чтение и разбор ответа JSON
ЧтениеJSON = Новый ЧтениеJSON;
ЧтениеJSON.УстановитьСтроку(СтрокаОтвета);
Результат = ПрочитатьJSON(ЧтениеJSON);
Если Ответ.КодСостояния = 200 Тогда
// Обработка успешного результата
Иначе
ВызватьИсключение "Ошибка API: " + СтрокаОтвета;
КонецЕсли;
КонецПроцедуры
Разберем важные архитектурные особенности при работе с криптографией в 1С:
System.Security.Cryptography доступны исключительно в среде ОС Windows. При переносе серверной части на Linux вызов COM-объекта приведет к ошибке.ХешированиеДанных поддерживает стандартные алгоритмы хэширования без секретного ключа (SHA-512, SHA-256), но не реализует вычисление HMAC.openssl через метод ЗапуститьПриложение или вынесение криптографических операций в отдельный микросервис-прокси.