Настройка аутентификации в 1С с использованием стандарта RFC 7519 (JWT)

27.02.24

Администрирование - Информационная безопасность

Рассмотрим в статье более подробную и последовательную настройку аутентификации в 1С с использованием распространенной технологии JWT, которая пришла в программу в платформе версии 8.3.21.1302.

В нашей конфигурации создадим HTTP-сервис.

 


Корневой URL у сервиса будет «auth».

 

.


Создаем шаблон URL с адресом «/service/». Создаем метод POST. Заполняем его свойства и делаем ему обработчик.

 


В базе данных создаем нового пользователя - AccessTokenGenerationUser. Задаем ему пароль «K3QvQz2y». Пользователь будет иметь свою отдельную роль с правами на вход в 1С и на наш POST-метод в HTTP-сервисе.

 

 

Далее создаем еще одного пользователя, под которым мы уже авторизуемся по JWT и получим доступ ко всем нашим сервисам в дальнейшем. Назовем его PublishingDatabaseService. В моем примере данный пользователь имеет полный доступ к взаимодействию со всеми сервисами, включая сервис с именем «Clients». При авторизации по определенному токену в сервис 1С мы авторизуемся как этот пользователь.

Модуль нашего сервиса аутентификации вместе с обработчиком выглядит следующим образом

 
 
#Область ОбработкаЗапросов

Функция СервисПолучитьТокен(HTTPЗапрос)
	
	ТелоHTTPОтвета = НовоеТелоHTTPОтвета();
	
	АвторизацияПоТокенамВключена = ПолучитьФункциональнуюОпцию("ЛМС_ИспользоватьТокеныДоступаДляАвторизацииСВнешнимиРесурсами");
	Если Не АвторизацияПоТокенамВключена Тогда
		
		ТелоHTTPОтвета.error = НСтр("ru = 'Авторизация по токенам JWT отключена.'", ОбщегоНазначения.КодОсновногоЯзыка()); 
		Возврат HTTPОтвет(ТелоHTTPОтвета, 500);
		
	КонецЕсли;
	
	ТелоЗапроса = HTTPЗапрос.ПолучитьТелоКакСтроку();
	ПараметрыЗапроса = ПрочитатьДанныеJSON(ТелоЗапроса);
	
	ИмяПолучателяТокена = Неопределено;
	ПараметрыЗапроса.Свойство("AccessTokenRecepientName", ИмяПолучателяТокена);
	
	Если ИмяПолучателяТокена = Неопределено Тогда
		
		ТелоHTTPОтвета.error = НСтр("ru = 'Получатель токена не найден.'", ОбщегоНазначения.КодОсновногоЯзыка()); 
		Возврат HTTPОтвет(ТелоHTTPОтвета, 500);
		
	КонецЕсли;
	
	КлючПодписи = КлючПодписиТокенаДоступа();
	
	ТокенДоступа = ТокенДоступаКВебСервису(ИмяПолучателяТокена, КлючПодписи);
	ТелоHTTPОтвета.AccessToken = ТокенДоступа;
	
	Возврат HTTPОтвет(ТелоHTTPОтвета);
	
КонецФункции 

#КонецОбласти // ОбработкаЗапросов

#Область СлужебныеПроцедурыИФункции

Функция НовоеТелоHTTPОтвета()
	
	Возврат Новый Структура("error, accessToken", "", Неопределено);
	
КонецФункции

Функция ТокенДоступаКВебСервису(ИмяПолучателяТокена, КлючПодписи)
	
	ТокенДоступа = Новый ТокенДоступа;
	ТокенДоступа.Заголовки.Вставить("alg", "HS256");
	
	ТокенДоступа.Эмитент                       = "ssl";
	ТокенДоступа.Получатели                    = ОбщегоНазначенияКлиентСервер.ЗначениеВМассиве(ИмяПолучателяТокена);
	ТокенДоступа.КлючСопоставленияПользователя = "Web_Service";
	ТокенДоступа.ВремяСоздания                 = ТекущаяУниверсальнаяДата() - Дата(1970,1,1,0,0,0);
	ТокенДоступа.ВремяЖизни                    = 60;
	ТокенДоступа.Идентификатор                 = Новый УникальныйИдентификатор;
	
	ТокенДоступа.Подписать(АлгоритмПодписиТокенаДоступа.HS256, КлючПодписи);
	
	Возврат Строка(ТокенДоступа);
	
КонецФункции

Функция КлючПодписиТокенаДоступа()
	
	Владелец = ОбщегоНазначения.ИдентификаторОбъектаМетаданных("Константа.ЛМС_ИспользоватьТокеныДоступаДляАвторизацииСВнешнимиРесурсами");
	Возврат ОбщегоНазначения.ПрочитатьДанныеИзБезопасногоХранилища(Владелец, "КлючПодписи");
	
КонецФункции

Функция HTTPОтвет(ОтправляемыеДанные, КодСостояния = 200)
	
	Ответ = Новый HTTPСервисОтвет(КодСостояния);
	Ответ.Заголовки.Вставить("Accept-Charset", "utf-8");
	Ответ.Заголовки.Вставить("Content-Type", "application/json;charset=utf-8");
	Ответ.Заголовки["Cache-Control"] = "no-cache";
	
	Ответ.УстановитьТелоИзСтроки(ЗаписатьДанныеJSON(ОтправляемыеДанные));
	
	Возврат Ответ;
	
КонецФункции

Функция ЗаписатьДанныеJSON(ДанныеДляЗаписи)
	
	ДанныеJSON = "";
	Если ДанныеДляЗаписи = Неопределено Тогда
		Возврат ДанныеJSON;
	КонецЕсли;
	
	Запись = Новый ЗаписьJSON;
	Запись.УстановитьСтроку(Новый ПараметрыЗаписиJSON);
	
	ЗаписатьJSON(Запись, ДанныеДляЗаписи);
	ДанныеJSON = Запись.Закрыть();
	
	Возврат ДанныеJSON;
	
КонецФункции

Функция ПрочитатьДанныеJSON(ДанныеJSON, ИменаСвойствСоЗначениямиДата = "")
	
	ЧтениеJSON = Новый ЧтениеJSON;
	ЧтениеJSON.УстановитьСтроку(ДанныеJSON);
	
	Возврат ПрочитатьJSON(ЧтениеJSON, , ИменаСвойствСоЗначениямиДата);
	
КонецФункции

#КонецОбласти // СлужебныеПроцедурыИФункции

 


Представление кода по созданию токена.

Функция ТокенДоступаКВебСервису(ИмяПолучателяТокена, КлючПодписи)
	
	ТокенДоступа = Новый ТокенДоступа;
	ТокенДоступа.Заголовки.Вставить("alg", "HS256");
	
	ТокенДоступа.Эмитент                       = "ssl";
	ТокенДоступа.Получатели                    = ОбщегоНазначенияКлиентСервер.ЗначениеВМассиве(ИмяПолучателяТокена);
	ТокенДоступа.КлючСопоставленияПользователя = "Web_Service";
	ТокенДоступа.ВремяСоздания                 = ТекущаяУниверсальнаяДата() - Дата(1970,1,1,0,0,0);
	ТокенДоступа.ВремяЖизни                    = 60;
	ТокенДоступа.Идентификатор                 = Новый УникальныйИдентификатор;
	
	ТокенДоступа.Подписать(АлгоритмПодписиТокенаДоступа.HS256, КлючПодписи);
	
	Возврат Строка(ТокенДоступа);
	
КонецФункции

 

Для формирования токена доступа в систему мы воспользуемся новым объектом «ТокенДоступа». Представим описание свойств данного объекта:

 

Свойства объекта ТокенДоступа

Свойства HTTP-сервиса в файле default.vrd

Описание свойства

Эмитент (соответствует ключу «iss»)

authenticationClaimName

Указывается как «ssl». Идентификатор приложения, выдавшего токен.

Получатели (соответствует ключу «aud»)

accessTokenRecepientName

Указывается идентификатор или любое другое значение в виде строки идентифицируя получателя токена.

КлючСопоставленияПользователя (соответствует ключу «sub»)

authenticationUserPropertyName

Указывается имя пользователя, под которым происходит аутентификация.

 

ВремяСоздания рассчитывается как ТекущаяУниверсальнаяДата() - Дата(1970,1,1,0,0,0). Это числовое значение времени создания токена доступа в формате UnixTime (количество секунд, прошедших с полуночи 01.01.1970).  Соответствует ключам «iat» и «nbf».

ВремяЖизни указывается в секундах. Можно выбрать любую продолжительность жизни токена. Устанавливает значение для ключа «exp» равное сумме времени создания и времени жизни.

КлючПодписи мы используем непосредственно в методе «ТокенДоступа.Подписать», но он также хранится в свойствах файла с именем «keyInformation».

Идентификатор является уникальным идентификатором токена. Соответствует ключу «jti».

Для получения токена мы выполняем обращение к нашему сервису авторизации.
Выполняем запрос с методом POST на адрес «localhost/edo/hs/auth/service/» с идентификационными данными в виде логина и пароля (AccessTokenGenerationUser, K3QvQz2y). Запрос должен включать в себя тело

 

 

Свойство AccessTokenRecepientName содержит идентификатор сервиса (к нему будет относиться будущий токен), с которым мы можем обращаться только к сервисам, где в файле default.vrd будет указано это же значение в свойстве AccessTokenRecepientName. В случае успеха получим такой ответ:

 

 

Ответ будет состоять из текста ошибки если что-то произошло не так и не удалось сформировать токен и самого токена в виде закодированной строки в формате Base64. Таким образом нам удалось сформировать наш токен и дальше мы можем с ним обратиться к своему HTTP-сервису. 

Содержимое полученного токена можно посмотреть с помощью сайта JWT.IO (справочная информация п. 3). 


 

Чтобы сервер аутентификации понял наш запрос с токеном, необходимо скорректировать данные сервиса в файле публикации. Заходим в файл default.vrd и находим там наш сервис (если он уже был опубликован ранее) или добавляем новый.

<service name="Клиенты"
        rootUrl="Clients"
        enable="true"
        reuseSessions="autouse"
        sessionMaxAge="20"
        poolSize="10"
        poolTimeout="5">
        <accessTokenAuthentication>
			<issuers>
				<issuer name="ssl" 
					authenticationClaimName="sub" 
					authenticationUserPropertyName="PublishingDatabaseService" 
					keyInformation="0J/RgNC40LLQtdGCINC80LjRgCE="/>
            </issuers>
			<accessTokenRecepientName>4e044f77-2563-4f19-bcee-fead012e2584</accessTokenRecepientName>
        </accessTokenAuthentication>
</service>

 


Добавляем в свойства пользователя PublishingDatabaseService информацию о том, что он может быть аутентифицирован с помощью токена доступа.

 


Отлично, теперь наша публикация откорректирована и мы можем обратиться к нашему сервису clients c целью получения информации о каком-нибудь клиенте.

ПараметрыЗапроса = Новый Структура;
ПараметрыЗапроса.Вставить("clientId", XMLСтрока(КлиентСсылка));

ТелоЗапроса = ЗаписатьДанныеJSON(ПараметрыЗапроса);

ШаблонСтроки = "http://%1/hs/clients/information";
СтрокаURI    = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(ШаблонСтроки, "localhost/edo");
СтруктураURI = ОбщегоНазначенияКлиентСервер.СтруктураURI(СтрокаURI);

HTTPЗапрос = Новый HTTPЗапрос(СтруктураURI.ПутьНаСервере);            
HTTPЗапрос.УстановитьТелоИзСтроки(ТелоЗапроса);

УстановитьПривилегированныйРежим(Истина);

ИспользоватьТокеныДоступа = ПолучитьФункциональнуюОпцию("ИспользоватьТокеныДоступаДляАвторизацииСВнешнимиРесурсами");
Если ИспользоватьТокеныДоступа Тогда
	HTTPЗапрос.Заголовки.Вставить("Authorization", "Bearer " + ТокенДоступаКВебСервису(ИдентификаторВебСервисаИнформацииОКлиентах()));
КонецЕсли;

РезультатВыполнения = ВыполнитьЗапрос(HTTPЗапрос, СтруктураURI, "GET");

Представление кода метода ВыполнитьЗапроса

 
 
Функция ВыполнитьЗапрос(HTTPЗапрос, СтруктураАдреса, HTTPМетод = "")
	
	Попытка
		
		HTTPСоединение = НовоеHTTPСоединение(СтруктураАдреса);
		
		Если ПустаяСтрока(HTTPМетод) Тогда
			HTTPОтвет = HTTPСоединение.ОтправитьДляОбработки(HTTPЗапрос);
		Иначе
			HTTPОтвет = HTTPСоединение.ВызватьHTTPМетод(HTTPМетод, HTTPЗапрос);
		КонецЕсли;
		
	Исключение
		
		ЗаписатьОшибкуВЖурналРегистрации(СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
		     НСтр("ru = 'Не удалось установить соединение с сервером %1 по причине:
		     |%2'"), СтруктураАдреса.Хост, ПодробноеПредставлениеОшибки(ИнформацияОбОшибке())));
		
		ВызватьИсключение; 
		
	КонецПопытки;
	
	Результат = Новый Структура;
	Результат.Вставить("ЗапросВыполнен", Ложь);
	Результат.Вставить("ОтветСервера", "");
	
	Если HTTPОтвет.КодСостояния = 401
		Или HTTPОтвет.КодСостояния = 403 Тогда
		
		ТекстОшибки = НСтр("ru = 'Не удалось пройти авторизацию на сервере.'"); 
		ЗаписатьОшибкуВЖурналРегистрации(ТекстОшибки);
		
		ВызватьИсключение ТекстОшибки;
		
	КонецЕсли;
	
	Результат.ЗапросВыполнен = HTTPОтвет.КодСостояния = 200;
	Результат.ОтветСервера = HTTPОтвет.ПолучитьТелоКакСтроку();
	
	Если Не Результат.ЗапросВыполнен Тогда
		
		ЗаписатьОшибкуВЖурналРегистрации(СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
		     НСтр("ru = 'Не удалось установить соединение с сервером %1 по причине:
		     |%2'"), СтруктураАдреса.Хост, Результат.ОтветСервера));
		
		ВызватьИсключение Результат.ОтветСервера;
		
	КонецЕсли;
	
	Возврат Результат;
	
КонецФункции

 

 

 
 
Функция НовоеHTTPСоединение(СтруктураURI, Таймаут = 60) Экспорт
	
	ИнтернетПрокси = Неопределено;
	
	Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.ПолучениеФайловИзИнтернета") Тогда
		МодульПолучениеФайловИзИнтернета = ОбщегоНазначения.ОбщийМодуль("ПолучениеФайловИзИнтернета");
		ИнтернетПрокси = МодульПолучениеФайловИзИнтернета.ПолучитьПрокси(СтруктураURI.Схема);
	КонецЕсли;
	
	ЗащищенноеСоединение = Неопределено;
	
	Если ВРег(СтруктураURI.Схема) = "HTTPS" Или ВРег(СтруктураURI.Схема) = "FTPS" Тогда
		ЗащищенноеСоединение = ОбщегоНазначенияКлиентСервер.НовоеЗащищенноеСоединение();
	КонецЕсли;
	
	Соединение = Новый HTTPСоединение(СтруктураURI.Хост, СтруктураURI.Порт, СтруктураURI.Логин, СтруктураURI.Пароль, ИнтернетПрокси, Таймаут, ЗащищенноеСоединение);
	
	Возврат Соединение;
	
КонецФункции

 

 

Справочные материалы

  1. Что такое токен и как он устроен https://its.1c.ru/db/v8321doc#bookmark:dev:TI000002522
  2. Описание полей элемента «accessTokenAuthentication» в файле публикации default.vrd https://its.1c.ru/db/v8321doc#bookmark:adm:TI000001102;
  3. Для экспериментов с различным наполнением JWT можно использовать сайт https://jwt.io.

Аутентификация1С

См. также

AUTO VPN (portable)

Информационная безопасность Системный администратор Программист Платные (руб)

Автоматизация подключения пользователей к удаленному рабочему месту или сети посредством создания автоматического VPN (L2TP или L2TP/IPSEC и т.д.) подключения без ввода настроек пользователем (с возможностью скрытия этих настроек от пользователя). Программа автоматически выполняет подключение к VPN серверу и после успешного коннекта , если необходимо, подключение к серверу удаленных рабочих столов (RDP).

1200 руб.

24.03.2020    14673    24    32    

34

Хранение секретов в Hashicorp Vault для 1С

Информационная безопасность Пароли Платформа 1С v8.3 Бесплатно (free)

Все еще храните пароли в базе? Тогда мы идем к вам! Безопасное и надежное хранение секретов. JWT авторизация. Удобный интерфейс. Демо конфигурация. Бесплатно.

30.05.2024    3725    kamisov    14    

56

Device flow аутентификация, или туда и обратно

Информационная безопасность Программист Платформа 1С v8.3 Абонемент ($m)

Интеграционные решения стали неотъемлемой частью нашей жизни. Правилом хорошего тона в современных приложениях является не давать интегратору доступ к чувствительным данным. Device flow позволяет аутентифицировать пользователя, не показывая приложению чувствительные данные (например: логин и пароль)<br> Рассмотрим Device flow аутентификацию, в приложении, на примере OpenID провайдера Yandex.

1 стартмани

27.10.2023    1979    platonov.e    1    

23

Анализатор безопасности базы сервера 1С

Информационная безопасность Системный администратор Платформа 1С v8.3 Конфигурации 1cv8 Россия Абонемент ($m)

Продукты на основе решений 1С уверенной поступью захватывают рынок учётных систем в стране. Широкое распространение программ всегда порождает большой интерес к ним со стороны злоумышленников, а пользователь 1С это одна из дверей в защищённый информационный контур предприятия. Обработка позволяет быстро и комплексно оценить настройки безопасности конкретной базы и возможности пользователя этой базы на сервере. Также можно оценить некоторые аспекты сетевой безопасности предприятия со стороны сервера 1С.

5 стартмани

24.04.2023    5721    18    soulner    7    

31

Двухфакторная аутентификация в 1С через Telegram и Email

Информационная безопасность Системный администратор Программист Платформа 1С v8.3 1С:ERP Управление предприятием 2 Абонемент ($m)

1С, начиная с версии платформы 8.3.21, добавили в систему возможность двойной аутентификации. Как это работает: в пользователе информационной базы появилось свойство «Аутентификация токеном доступа» (АутентификацияТокеномДоступа во встроенном языке), если установить этот признак и осуществить ряд манипуляций на встроенном языке, то появляется возможность при аутентификации отправлять HTTP запросы, которые и реализуют этот самый второй фактор. Данное расширение позволяет организовать двухфакторную аутентификацию с помощью электронной почты или мессенджера Telegram.

2 стартмани

08.12.2022    6346    36    Silenser    12    

23

История одного взлома или проверьте вашу систему на безопасность

Информационная безопасность Платформа 1С v8.3 Конфигурации 1cv8 Бесплатно (free)

От клиента клиенту, от одной системы к другой, мы вновь и вновь встречаем одни и те же проблемы и дыры в безопасности. На конференции Infostart Event 2021 Post-Apocalypse Виталий Онянов рассказал о базовых принципах безопасности информационных систем и представил чек-лист, с помощью которого вы сможете проверить свою систему на уязвимость.

26.10.2022    9762    Tavalik    46    

114
Комментарии
Подписаться на ответы Инфостарт бот Сортировка: Древо развёрнутое
Свернуть все
1. fomix 33 28.02.24 07:53 Сейчас в теме
Про http сервис более, чем понятно. А вот тема зачем всё это нужно вообще не раскрыта.
dabu-dabu; Sergik_D; SP2000; PROSTO-1C; ixijixi; +5 Ответить
2. PROSTO-1C 1110 28.02.24 11:47 Сейчас в теме
(1) Спасибо, мы рады, что получилось понятно написать инструкцию. Мы не хотели повторяться и дублировать информацию — «зачем все это нужно» можно посмотреть в документации 1С https://its.1c.ru/db/v8321doc#bookmark:dev:TI000002523
3. kamisov 210 29.02.24 11:03 Сейчас в теме
Жаль только, что 1С формирует неправильные JWT. И понимает созданные в 1С JWT только сама 1С. Потому что поля nbf и iat должны быть числами, а не строками. То что они строки - видно на вашем же скриншоте с JWT.io

Если навести курсор на значения nbf и iat на сайте - он покажет «invalid что-то там».

Ждём когда 1С починит формирование JWT.
kaaasteeen; JohnyDeath; bettereatnuts; PROSTO-1C; +4 Ответить
4. amoarok 99 29.02.24 21:59 Сейчас в теме
(3) можно ждать, а можно формировать токены вручную. Код совсем не сложный получается.
Главное что http-сервисы платформы умеют корректно обрабатывать как "неправильные" JWT, так и правильные.
PROSTO-1C; +1 Ответить
5. kamisov 210 29.02.24 23:12 Сейчас в теме
(4) есть пример совсем несложного кода для линукса? Только для винды видел с использованием ком-объектов из дотнета.
6. amoarok 99 01.03.24 00:07 Сейчас в теме
(5) для симметричного шифрования, как в статье, есть готовая библиотека: https://github.com/pintov/1c-jwt
Для RSA можно например воспользоваться OpenSSL для подписания. Но и на чистом 1Сном коде реально написать - у нас в проде такое крутится, но там уже сложновато. Я честно говоря был удивлён когда понял что 1С в качестве числодробилки может оперировать с ОЧЕНЬ большими числами.
PROSTO-1C; +1 Ответить
7. kamisov 210 01.03.24 00:30 Сейчас в теме
(6) в общем, костыли :) А хотелось от 1С, конечно, увидеть работающий токен доступа.
8. user612295_death4321 03.03.24 17:31 Сейчас в теме
(3)
Ждём когда 1С починит формирование JWT.


Ты ведь оформил тикет в 1С ?)
9. kamisov 210 03.03.24 17:51 Сейчас в теме
(8) да, и ждал 3 месяца пока зарегистрируют. Теперь буду ждать 100 лет когда починят.
10. AntonKite 23.04.24 08:24 Сейчас в теме
Уже была аналогичная статья, в которой визуально показали связь между созданием токена доступа и файлом публикации.
+ есть описание как создавать и применять полученные токены доступа для авторизации в веб и тонком клиентах.
https://forum.infostart.ru/forum15/topic294665/#message3042387
Оставьте свое сообщение