При организации обмена данными между 1С и веб-сайтом (например, на PHP/MySQL) часто возникает задача авторизации пользователей. Серверы обычно хранят пароли не в открытом виде, а в виде хэш-сумм (например, MD5 или SHA-256), часто с добавлением секретного ключа (соли). Разберем, как корректно сформировать хэш пароля на стороне 1С, избежав типичных ошибок с кодировками и типами данных.
Выясним, почему хэш-сумма, сгенерированная в 1С, может не совпадать с результатом работы функции md5() в PHP или почему функции кодирования возвращают пустое значение:
Base64Значение() в 1С предназначена для декодирования строки, которая уже закодирована в формате Base64, в тип ДвоичныеДанные. Если передать в нее обычную строку пароля, система вернет пустой результат или вызовет ошибку.Рассмотрим наиболее верный кроссплатформенный подход, встроенный в платформу 1С:Предприятие 8.3. Он работает как на Windows, так и на Linux-серверах без сторонних библиотек.
Для получения корректного хэша переведем строку в двоичные данные в кодировке UTF-8, после чего рассчитаем хэш-сумму:
Функция ПолучитьХешMD5_Встроенный(Знач СтрокаПароля)
// Переводим строку в двоичные данные UTF-8
ДвоичныеДанные = ПолучитьДвоичныеДанныеИзСтроки(СтрокаПароля, "UTF-8", Ложь);
// Вычисляем хэш MD5
ОбъектХеш = Новый ХешированиеДанных(ХешФункция.MD5);
ОбъектХеш.Добавить(ДвоичныеДанные);
// Получаем строку в шестнадцатеричном виде в нижнем регистре
СтрокаХеша = НРегистр(Строка(ОбъектХеш.ХешСумма));
Возврат СтрокаХеша;
КонецФункции
Если на стороне PHP используется подмешивание соли (например, md5($password . $salt)), то в 1С перед передачей в функцию необходимо просто конкатенировать строку пароля и соль: ПолучитьХешMD5_Встроенный(Пароль + Соль).
Посмотрим на пример использования системных COM-объектов Windows .NET framework. Данный метод подходит для работы в среде Windows:
&НаСервере
Функция ВернутьХэшСтрокиNET(ВхСтрока)
Попытка
оMD5 = Новый COMОбъект("System.Security.Cryptography.MD5CryptoServiceProvider");
оEnc = Новый COMОбъект("System.Text.UTF8Encoding");
оStr = Новый COMОбъект("System.Text.StringBuilder");
// Преобразуем строку в байтовый массив UTF-8
Массив = оEnc.GetBytes_4(ВхСтрока);
// Вычисляем MD5 хэш
Массив = оMD5.ComputeHash_2(Массив);
// Переводим массив байт в шестнадцатеричную строку
КолЭлементовМассива = Массив.GetLength();
Для Ит = 0 ПО КолЭлементовМассива - 1 Цикл
оStr.AppendFormat("{0:x02}", Массив.GetValue(Ит));
КонецЦикла;
Возврат оStr.ToString();
Исключение
ЗаписьЖурналаРегистрации("Ошибка MD5", УровеньЖурналаРегистрации.Ошибка,,, ОписаниеОшибки());
Возврат Неопределено;
КонецПопытки;
КонецФункции
Проанализируем еще один альтернативный вариант для Windows-клиентов — выполнение JavaScript-кода хеширования с помощью COM-объекта MSScriptControl.ScriptControl:
Функция ПолучитьMD5_ScriptControl(КодируемаяСтрока)
Попытка
ScrptCtrl = Новый COMОбъект("MSScriptControl.ScriptControl");
ScrptCtrl.Language = "JScript";
ScrptCtrl.AddCode("
|var chrsz = 8;
|function hex_md5(s){ return binl2hex(core_md5(str2binl(s), s.length * chrsz));}
|function core_md5(x, len) {
| x[len >> 5] |= 0x80 << ((len) % 32);
| x[(((len + 64) >>> 9) << 4) + 14] = len;
| var a = 1732584193, b = -271733879, c = -1732584194, d = 271733878;
| for(var i = 0; i < x.length; i += 16) {
| var olda = a, oldb = b, oldc = c, oldd = d;
| a = md5_ff(a, b, c, d, x[i+0], 7 , -680876936);
| d = md5_ff(d, a, b, c, x[i+1], 12, -389564586);
| c = md5_ff(c, d, a, b, x[i+2], 17, 606105819);
| b = md5_ff(b, c, d, a, x[i+3], 22, -1044525330);
| a = safe_add(a, olda); b = safe_add(b, oldb); c = safe_add(c, oldc); d = safe_add(d, oldd);
| }
| return Array(a, b, c, d);
|}
|function md5_cmn(q, a, b, x, s, t) { return safe_add(bit_rol(safe_add(safe_add(a, q), safe_add(x, t)), s),b); }
|function md5_ff(a, b, c, d, x, s, t) { return md5_cmn((b & c) | ((~b) & d), a, b, x, s, t); }
|function safe_add(x, y) { var lsw = (x & 0xFFFF) + (y & 0xFFFF); var msw = (x >> 16) + (y >> 16) + (lsw >> 16); return (msw << 16) | (lsw & 0xFFFF); }
|function bit_rol(num, cnt) { return (num << cnt) | (num >>> (32 - cnt)); }
|function str2binl(str) { var bin = Array(); var mask = (1 << chrsz) - 1; for(var i = 0; i < str.length * chrsz; i += chrsz) bin[i>>5] |= (str.charCodeAt(i / chrsz) & mask) << (i%32); return bin; }
|function binl2hex(binarray) { var hex_tab = ""0123456789abcdef""; var str = """"; for(var i = 0; i < binarray.length * 4; i++) str += hex_tab.charAt((binarray[i>>2] >> ((i%4)*8+4)) & 0xF) + hex_tab.charAt((binarray[i>>2] >> ((i%4)*8)) & 0xF); return str; }
|");
Возврат ScrptCtrl.Run("hex_md5", КодируемаяСтрока);
Исключение
Сообщить(ОписаниеОшибки());
Возврат Неопределено;
КонецПопытки;
КонецФункции
Разберем основные правила защиты данных при передаче запросов из 1С на веб-сайт:
HTTPСоединение следует выполнять по протоколу HTTPS. Шифрование на уровне TLS предотвращает перехват любых параметров POST-запроса в открытом виде.ХешФункция.SHA256.