HMAC на встроенном языке 1С




Принцип обмена данными из 1С с сайтом (на MySQL) и выдачи (публикации) этих данных по запросу.
PHP-Скрипт автоматической загрузки данных из файла данных в формате CSV в базу данных сайта работающего на WordPress.

В продолжение моей темы: 1С:Альфа-Авто Автосалон Автосервис: обмен с сайтом.
С помощью данного скрипта можно загружать в автоматическом режиме, по расписанию, данные сервисных книжек (ремонтов авто) из 1С:Альфа-Авто Автосалон Автосервис.
Также можно загружать данные в ручном режиме: для этого делается скрытая страница, где размещается специальная кнопка.
Комментарии размещенные внутри скрипта разъяснят логику и порядок действия.
Комментарии с "/////    echo" использовались для отладки.
Дополнительно создана таблица для журналирования результатов загрузки данных.
Скрипт включает в себя защиту от SQL инъекций (думаю безопасность соблюдена в полной мере).
В кратце:
1. Пишется скрипт, который запускает этот.
2. Создается регламентное задание в WordPress, по которому запускается скрипт из п.1. 
3. Этот скрипт осуществляет проверку на существование файла обмена в папке.
4. Если данные не новые, загрузка не производится.
5. Если данные новые, очищается таблица сервисных книжек.
6. Загружаются новые данные.

Собственно сам скрипт:

<?php // Полная загрузка сервисных книжек, создан 2024-01-05 12:44:55

global $wpdb2;
global $failure;
global $file_hist;

/////  echo '<H2><b>Старт загрузки</b></H2><br>';

$failure=FALSE;
//подключаемся к базе
$wpdb2 = include_once 'connection.php'; ; // подключаемся к MySQL
// если не удалось подключиться, и нужно оборвать PHP с сообщением об этой ошибке
if (!empty($wpdb2->error))
{
/////   echo '<H2><b>Ошибка подключения к БД, завершение.</b></H2><br>';
$failure=TRUE;
wp_die( $wpdb2->error );
}

$m_size_file=0;
$m_mtime_file=0;
$m_comment='';
/////проверка существования файлов выгрузки из 1С
////файл выгрузки сервисных книжек
$file_hist = ABSPATH.'/_1c_alfa_exchange/AA_hist.csv';
if (!file_exists($file_hist))
{
/////   echo '<H2><b>Файл обмена с сервисными книжками не существует.</b></H2><br>';
$m_comment='Файл обмена с сервисными книжками не существует';
$failure=TRUE;
}

/////инициируем таблицу лога
/////если не существует файла то возврат и ничего не делаем
if ($failure){
///включает защиту от SQL инъекций и данные можно передавать как есть, например: $_GET['foo']
/////   echo '<H2><b>Попытка вставить запись в лог таблицу</b></H2><br>';
$insert_fail_zapros=$wpdb2->insert('vin_logs', array('time_stamp'=>time(),'last_mtime_upload'=>$m_mtime_file,'last_size_upload'=>$m_size_file,'comment'=>$m_comment));
wp_die();
/////    echo '<H2><b>Возврат в начало.</b></H2><br>';
return $failure;
}
/////проверка лога загрузки, что бы не загружать тоже самое
$masiv_data_file=stat($file_hist);   ////передаем в массив свойство файла
$m_size_file=$masiv_data_file[7];    ////получаем размер файла
$m_mtime_file=$masiv_data_file[9];   ////получаем дату модификации файла
////создаем запрос на получение последней удачной загрузки
////выбираем по штампу времени создания (редактирования) файла загрузки AA_hist.csv, $m_mtime_file

/////   echo '<H2><b>Размер файла: '.$m_size_file.'</b></H2><br>';
/////   echo '<H2><b>Штамп времени файла: '.$m_mtime_file.'</b></H2><br>';
/////   echo '<H2><b>Формирование запроса на выборку из лога</b></H2><br>';
////препарируем запрос
$text_zaprosa=$wpdb2->prepare("SELECT * FROM `vin_logs` WHERE `last_mtime_upload` = %s", $m_mtime_file);
$results=$wpdb2->get_results($text_zaprosa);

if ($results)
{   foreach ( $results as $r)
{
////если штамп времени и размер файла совпадают, возврат
if (($r->last_mtime_upload==$m_mtime_file) && ($r->last_size_upload==$m_size_file))
{////echo '<H2><b>Возврат в начало, т.к. найдена запись в логе.</b></H2><br>';
$insert_fail_zapros=$wpdb2->insert('vin_logs', array('time_stamp'=>time(),'last_mtime_upload'=>$m_mtime_file,'last_size_upload'=>$m_size_file,'comment'=>'Загрузка отменена, новых данных нет, т.к. найдена запись в логе.'));
wp_die();
return $failure;
}
}
}
////если данные новые, пишем в лог запись о начале загрузки
/////echo '<H2><b>Попытка вставить запись о начале загрузки в лог таблицу</b></H2><br>';
$insert_fail_zapros=$wpdb2->insert('vin_logs', array('time_stamp'=>time(),'last_mtime_upload'=>0, 'last_size_upload'=>$m_size_file, 'comment'=>'Начало загрузки'));

////очищаем таблицу
$clear_tbl_zap=$wpdb2->prepare("TRUNCATE TABLE %s", 'vin_history');
$clear_tbl_zap_repl=str_replace("'","`",$clear_tbl_zap);
$results=$wpdb2->query($clear_tbl_zap_repl);
/////   echo '<H2><b>Очистка таблицы сервисных книжек</b></H2><br>';
if (empty($results))
{
/////   echo '<H2><b>Ошибка очистки таблицы книжек, завершение.</b></H2><br>';
//// если очистка не удалась, возврат
$failure=TRUE;
wp_die();
return $failure;
}

////загружаем данные
$table='vin_history';         // Имя таблицы для импорта
//$file_hist Имя CSV файла, откуда берется информация     // (путь от корня web-сервера)
$delim=';';          // Разделитель полей в CSV файле
$enclosed='"';      // Кавычки для содержимого полей
$escaped='\

35 Comments

  1. i_lo

    Скопировал код из статьи в обработку. Ввожу ключ — 123, текст — sss, функцию — sha-1 и получаю hmac — da2a7fa2ac3e18892b6d0d24221285fa1030b03d. Разве он не должен быть, как на скриншоте 83е…?

    Ввожу ключ — 123456, тест — Вышел зайчик погулять, функцию — sha-1 и получаю:

    {ВнешняяОбработка.HMAC.МодульОбъекта(74)}: Ошибка при вызове метода контекста (Создать)

    ДвоичныеДанные = ФабрикаXDTO.Создать(ТипhexBinary,nString);

    по причине:

    Несоответствие типов XDTO

    по причине:

    Ошибка проверки данных XDTO:

    Значение: ‘24026036363636363636363636363636363636363636363636363636363­636363636363636363636363636363636363636363636363636363636363­63636363641244b44843543b2043743043944743843a2043f43e43b44343­b44f44244c’ не соответствует простому типу: {http://www.w3.org/2001/XMLSchema}hexBinary

    Reply
  2. Knup

    (1)

    Разве он не должен быть, как на скриншоте 83е…?

    нет, потому что ключ нужно передавать в шестнадцатеричном виде.

    (1)

    Ввожу ключ — 123456, тест — Вышел зайчик погулять, функцию — sha-1 и получаю:

    Добавил поддержку кирилицы

    Reply
  3. Knup

    (1)

    Разве он не должен быть, как на скриншоте 83е…?

    в файле обработки есть пример

    Reply
  4. Операция1Ы

    на 8.2 работать не будет, там нет ХешированиеДанных.

    Reply
  5. Knup

    (4) к сожелению, да. Если хеширование sha1, тогда посмотрите http://infostart.ru/public/99739/ готовое решение.

    Reply
  6. user839842

    пробовал реализовать sha256 на приведенном примере. Но хеш получается другой. Нежели генерировать его в online конвертерах. В коде какая-то ошибка ?

    Reply
  7. Knup

    (6) Какой текст и ключ? У меня все работает как часы

    Reply
  8. V_K

    Функция HMAC(Знач K, Знач text, Знач Hash)

    А если ключ «K» это строка,а не число. Как его зашифровать в этот параметр?

    Reply
  9. Knup

    (8) Вводите строку, все должно работать (:

    Reply
  10. primat

    Владимир, подскажите, пожалуйста, если мне нужно хеширование SHA-384, то получится ли использовать вместо функции SHA1(Знач nString, Hash) из Вашего алгоритма функцию из этого примера? https://1c-programmer-blog.ru/programmirovanie/md5-v-1s.html

    Например, ту, что использует библиотеку CAPICOM. Ведь хеширования SHA-384 у 1С нет в платформе, верно?

    Reply
  11. Knup

    (10) Да, все будет работать.

    И да, хеширования SHA-384 в 1С нет (:

    Reply
  12. sudden

    Помогите пожалуйста.

    АПИСекрет = «cEMBFULinI6rzG3mYKL45czc81pjU7BXbwImC1CFNXk»;

    Сигнатура = «8692c7a03a684765ac5fe04f04dd72c8POSThttps://localhost/api/getopenorders11223311FxOYiYfpMxmANj4kGJzg==»­

    хмак = HMAC(АПИСекрет, Сигнатура, «SHA256»);

    На выходе 224c54567d42c5c3537bc305329694347fba095592094d6e88a2f342e788­ec1e

    PHP:

    $hmacsignature = base64_encode( hash_hmac(«sha256», $signature, base64_decode( $API_SECRET ), true ) );

    На выходе: v+YF+qxhVqB95bjKZB7bN7ywpTgoPUleObTmXNoEE2E=

    Расскажите что не так?

    Reply
  13. Knup

    (12) Судя по всему в коде php у вас не просто получается hmac, а еще использует кодирование информации в 64-разрядный код. В публикации функция просто получает HMAC. Попробуйте получить по этим данным HMAC в онлайн генераторе и 1С. Результат будет одинаковый.

    Reply
  14. lamdth

    тоже интересно, можно ли как-то доработать обработку чтобы получить HMAC в Base 64

    Reply
  15. Knup

    (14) Конечно можно. Посмотрите на сайте https://infostart.ru/public/all/?st=t&public-filter%5Bsearch%5D=base64, или поищите в интернете. Скорее всего Вашу проблему уже кто-то решал.

    Reply
  16. sudden

    (13) Все равно не то что-то. Секрет передать в каком виде надо?

    АПИСекрет = «cEMBFULinI6rzG3mYKL45czc81pjU7BXbwImC1CFNXk»;

    Потому что даже убрав base64_encode из ПХП получая по

    $hmacsignature = hash_hmac(«sha256», $signature, base64_decode( $API_SECRET ), true ) ;

    Ответы разные.

    Остается только в обработке Первое: base64_decode( $API_SECRET ) и Второе: hash_hmac(«sha256»,$signature, Результат_Первого), В_Двоичных)

    Но даже получив ответ от ПХП не двоичные данные, а в шестнадцатеричной кодировке = Разные.

    Reply
  17. sudden

    hash_hmac(«»sha256″», $signature, $API_SECRET, false )

    Даже так разное

    Reply
  18. Knup

    (16) Сложно сказать основываясь на вашем коде, что именно происходит. Предлагаю вам воспользоватся онлайн генератором https://www.freeformatter.com/hmac-generator.html. Введите туда

    АПИСекрет = «cEMBFULinI6rzG3mYKL45czc81pjU7BXbwImC1CFNXk»;

    Сигнатура = «8692c7a03a684765ac5fe04f04dd72c8POSThttps://localhost/api/getopenorders11223311FxOYiYfpMxmANj4kGJzg==»­­;

    и результат у вас получится аналогичный с результатом в 1С,

    Повторюсь ищите причину в php, судя по всему там не просто хеширование в hmac

    Reply
  19. vl-sher1

    Владимир, спасибо за процедуру. Она некорректно работала с кодировкой UTF8, я бы предложил сделать так (8.3):

    Функция HMAC(Знач K, Знач text, Знач Hash, Кодировка = null ) Экспорт
    
    Перем kResult;
    Перем К0;
    
    Если Кодировка = null Тогда Кодировка = КодировкаТекста.UTF8; КонецЕсли;
    // …
    //3 Выполняем склейку исходного сообщения со строкой, полученной на шаге 2.    БуферДвоичныхДанных
    ДвоичныйТекст = ПолучитьБуферДвоичныхДанныхИзСтроки(text, Кодировка, ложь);
    Для к = 0 По ДвоичныйТекст.Размер — 1 Цикл
    StringSHA1 = StringSHA1 + ПреобразоватьДесятичнуюСИВHex(ДвоичныйТекст[к]);
    КонецЦикла;
    

    Показать

    Для проверки удобно использовать https://www.freeformatter.com/hmac-generator.html

    Reply
  20. unoDosTres

    Доброго дня! Подскажите ,выложенный в публикации код такой же как и в обработке?

    потому что воспользовавшись, кодом из публикации и попытавшись сравнить результат с онлайн генератором предложенным автором, ни разу не получил сходство ни по одному из алгоритмов шифрования. прикрепил файл

    Reply
  21. Knup

    (20) День добрый! Код абсолютно идентичный. Проверил, у меня все работает на вашем примере. Посмотрите на описание передаваемых параметров и их формат, Вы точно правильно передаете их? Хочу обратить Ваше внимание на параметр K — ключ, он передается в шестнадцатеричном виде.

    Reply
  22. unoDosTres

    (21),

    Т.е. в моем примере на скрине у меня ключ имеет строковое значение «key» я его должен перевести в hex и только после этого запускать функцию hmac?

    Reply
  23. Knup

    (22) Именно так

    Reply
  24. afafaf

    (23) Подскажите, пожалуйста, как именно это сделать (привести строку к hex виду)?

    Reply
  25. Knup

    (24)

    kKey = «»;
    Для к = 1 ПО СтрДлина(Key) Цикл
    
    kKey = kKey + ПреобразоватьДесятичнуюСИВHex(КодСимвола(Сред(Key,к,1)));
    
    КонецЦикла; 
    Reply
  26. afafaf

    А вот мой вариант. Строго в соответствии с алгоритмом из Вики (единственное отличие — предварительно от ключа рассчитывается MD5, это требуется в конкретно моей реализации, можно убрать)

    Функция Шмяк(СтрокаТекст,СтрокаКлюч) Экспорт
    
    СтрокаНули = «00000000000000000000000000000000000000000000000000000000000­000000000000000000000000000000000000000000000000000000000000­000000000″;
    СтрокаОПАД = «5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5­c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5c5­c5c5c5c5c»;
    СтрокаИПАД = «36363636363636363636363636363636363636363636363636363636363­636363636363636363636363636363636363636363636363636363636363­636363636″;
    
    К = ПолучитьДвоичныеДанныеИзСтроки(СтрокаКлюч);
    ХД = Новый ХешированиеДанных(ХешФункция.MD5);
    ХД.Добавить(К);
    Шаг0 = ХД.ХешСумма;
    
    К = ПолучитьБуферДвоичныхДанныхИзДвоичныхДанных(Шаг0);
    Нули = ПолучитьБуферДвоичныхДанныхИзHexСтроки(СтрокаНули);
    Нули.ЗаписатьПобитовоеИли(0,К);
    Шаг1 = ПолучитьДвоичныеДанныеИзБуфераДвоичныхДанных(Нули);
    
    ИПАД = ПолучитьБуферДвоичныхДанныхИзHexСтроки(СтрокаИПАД);
    БуферШаг1 = ПолучитьБуферДвоичныхДанныхИзДвоичныхДанных(Шаг1);
    ИПАД.ЗаписатьПобитовоеИсключительноеИли(0,БуферШаг1);
    Шаг2 = ПолучитьДвоичныеДанныеИзБуфераДвоичныхДанных(ипад);
    
    БуферШаг2 = ПолучитьБуферДвоичныхДанныхИзДвоичныхДанных(Шаг2);
    БуферТекст = ПолучитьБуферДвоичныхДанныхИзСтроки(СтрокаТекст);
    БуферШаг3 = БуферШаг2.Соединить(БуферТекст);
    Шаг3 = ПолучитьДвоичныеДанныеИзБуфераДвоичныхДанных(БуферШаг3);
    
    ХД = Новый ХешированиеДанных(ХешФункция.SHA1);
    ХД.Добавить(Шаг3);
    Шаг4 = ХД.ХешСумма;
    
    ОПАД = ПолучитьБуферДвоичныхДанныхИзHexСтроки(СтрокаОПАД);
    БуферШаг1 = ПолучитьБуферДвоичныхДанныхИзДвоичныхДанных(Шаг1);
    ОПАД.ЗаписатьПобитовоеИсключительноеИли(0,БуферШаг1);
    Шаг5 = ПолучитьДвоичныеДанныеИзБуфераДвоичныхДанных(ОПАД);
    
    БуферШаг4 = ПолучитьБуферДвоичныхДанныхИзДвоичныхДанных(Шаг4);
    БуферШаг5 = ПолучитьБуферДвоичныхДанныхИзДвоичныхДанных(Шаг5);
    БуферШаг6 = БуферШаг5.Соединить(БуферШаг4);
    Шаг6 = ПолучитьДвоичныеДанныеИзБуфераДвоичныхДанных(БуферШаг6);
    
    ХД = Новый ХешированиеДанных(ХешФункция.SHA1);
    ХД.Добавить(Шаг6);
    Шаг7 = ХД.ХешСумма;
    
    Возврат ПолучитьHexСтрокуИзДвоичныхДанных(Шаг7);
    
    КонецФункции
    
    

    Показать

    Reply
  27. inf012

    Здравствуйте.

    Я не понял, SHA-256 работает в 8.3 без использования внешних компонент?

    Нужно в мобильное приложение вставить шифрование SHA-256?

    Есть примеры кода?

    Reply
  28. Knup

    (27)

    Здравствуйте!

    Есть, есть и даже поддерживает мобильное приложение

    Хеширование        = Новый ХешированиеДанных(ХешФункция.SHA256);
    Хеширование.Добавить(«<Строка для хеш функции>»);
    SHA256             = Хеширование.ХешСумма;
    Reply
  29. Юрий-К

    Функция — HMAC есть давней в публикации https://infostart.ru/public/458286/

    Reply
  30. SuperSpade

    (25)Спасибо. Помогло.

    Reply
  31. Dilovar9

    Спасибо!

    Reply
  32. ZeratulAyuris

    (26) спасибо за вариант, но к нему есть дополнение для случаев, когда длина ключа >64 байт:

    Шаг0 = ПолучитьДвоичныеДанныеИзСтроки(СтрокаКлюч);
    Если Шаг0.Размер() > 64 Тогда
    ХД = Новый ХешированиеДанных(ХешФункция.MD5);
    ХД.Добавить(Шаг0);
    Шаг0 = ХД.ХешСумма;
    КонецЕсли;
    
    Reply
  33. Dan1c28

    через MD5 у меня не совпадает hmac 🙁

    Reply
  34. Dan1c28

    Вызываю вашу функцию,

    keyss = «TESTTEST»;
    Подпись = «6create36850d51d1-5ed7-11e2-8161-001a6411168d11107900000000»;
    
    HMAC(keyss, Подпись, «MD5»);

    В итоге различный хэш, если сгенерировать через сайт hmac hash.

    Мой результат: ba60785f34fa7342118a36399be364c3

    На сайте: c8c639dc293e0b25459e36e073d33430

    Или ваша функция только для sha1 предназначена?

    Reply
  35. Knup

    (35) Прочитайте (25) там ответ на ваш вопрос

    Reply

Leave a Comment

Ваш адрес email не будет опубликован. Обязательные поля помечены *