При разработке интеграций, требующих использования электронной подписи (например, для взаимодействия с ГИС МТ «Честный знак»), программисты 1С часто сталкиваются с проблемой: сертификат, который прекрасно виден в обычной сессии пользователя или во внешней обработке, категорически «не виден» коду, исполняемому внутри веб-сервиса. Рассмотрим подробнее, почему это происходит и как настроить систему для корректной работы с криптографией.
Проанализируем ситуацию: веб-сервис 1С публикуется на веб-сервере (обычно Apache или IIS). Когда внешний клиент обращается к методу веб-сервиса, 1С выполняет этот код на стороне сервера. Проблема заключается в том, что по умолчанию службы веб-серверов запускаются от имени специальных системных учетных записей (например, LocalSystem, NetworkService или IUSR). У этих учетных записей есть свои собственные, зачастую пустые, хранилища сертификатов. Личное хранилище (Personal) того пользователя, под которым вы заходили в Windows и устанавливали сертификат, для этих системных служб просто недоступно.
Разберем типовой код, который может выдавать ошибку или возвращать Неопределено при запуске в контексте веб-сервиса:
// Попытка получения хранилища в серверном модуле веб-сервиса
МенеджерКриптографии = Новый МенеджерКриптографии("", "", 80);
ХранилищеСертификатов = МенеджерКриптографии.ПолучитьХранилищеСертификатов(ТипХранилищаСертификатовКриптографии.ПерсональныеСертификаты);
// Поиск по отпечатку вернет Неопределено, если сертификат в хранилище другого пользователя
Сертификат = ХранилищеСертификатов.НайтиПоОтпечатку(ДвоичныеДанныеОтпечатка);
Если в качестве веб-сервера используется Apache, самым быстрым и эффективным решением будет изменение учетной записи, от имени которой работает служба. Рассмотрим этот процесс по шагам:
Apache2.4 (или вашу версию).После этих манипуляций метод МенеджерКриптографии.ПолучитьХранилищеСертификатов начнет обращаться к хранилищу именно этого пользователя, и сертификат будет успешно найден.
При использовании Internet Information Services (IIS) ситуация несколько сложнее. Даже если вы настроите пул приложений на работу от имени нужного пользователя, этого может быть недостаточно. Выясним причину: IIS по умолчанию не загружает профиль пользователя полностью.
Проанализируем необходимые настройки в IIS:
True.Если этого не сделать, система не увидит ветку реестра HKEY_CURRENT_USER, где и располагается информация о личном хранилище сертификатов, что приведет к ошибке открытия хранилища (часто с кодом 0x00000005 — доступ запрещен).
Нахождение сертификата в хранилище — это только первый этап. Для выполнения операции Подписать() серверу необходим доступ к закрытому ключу. Посмотрим, как предоставить этот доступ явно:
Если архитектура решения позволяет, рассмотрим вариант установки сертификата в хранилище Локального компьютера (Local Machine), а не текущего пользователя. Это позволит любому процессу на сервере (при наличии прав на ключи) обращаться к сертификату независимо от того, под каким пользователем запущен сервис.
При таком подходе в коде 1С необходимо использовать соответствующие параметры при инициализации хранилища. Однако помните, что при импорте сертификата в машинное хранилище необходимо убедиться, что криптопровайдер (например, КриптоПро CSP) корректно видит контейнер закрытого ключа в машинном контексте.
Рассмотрим более развернутый пример функции, которая может быть использована в веб-сервисе для получения списка доступных сертификатов и последующего подписания. Обратите внимание на использование объекта МенеджерКриптографии.
&НаСервере
Функция ПолучитьСертификатПоОтпечатку(ОтпечатокСтрокой)
// Инициализируем менеджер криптографии
// Параметры зависят от установленного CSP (КриптоПро, ViPNet и т.д.)
Менеджер = Новый МенеджерКриптографии("", "", 80);
// Получаем личное хранилище текущего пользователя процесса
Хранилище = Менеджер.ПолучитьХранилищеСертификатов(ТипХранилищаСертификатовКриптографии.ПерсональныеСертификаты);
// Преобразуем строковый отпечаток в двоичные данные
ДвоичныеДанныеОтпечатка = ПолучитьДвоичныеДанныеИзГексагональнойСтроки(ОтпечатокСтрокой);
Сертификат = Хранилище.НайтиПоОтпечатку(ДвоичныеДанныеОтпечатка);
Если Сертификат = Неопределено Тогда
ЗаписатьЛогСобытий("Сертификат с отпечатком " + ОтпечатокСтрокой + " не найден в хранилище.");
Возврат Неопределено;
КонецЕсли;
Возврат Сертификат;
КонецФункции
&НаСервере
Процедура ПодписатьДанные(ПутьКФайлу, Отпечаток)
Сертификат = ПолучитьСертификатПоОтпечатку(Отпечаток);
Если Сертификат = Неопределено Тогда
ВызватьИсключение "Ошибка: Сертификат не найден.";
КонецЕсли;
Менеджер = Новый МенеджерКриптографии("", "", 80);
// Если контейнер защищен паролем, его нужно передать здесь
Менеджер.ПарольДоступаКЗакрытомуКлючу = "ваш_пароль";
ПутьКПодписанномуФайлу = ПутьКФайлу + ".sig";
Попытка
Менеджер.Подписать(ПутьКФайлу, ПутьКПодписанномуФайлу, Сертификат);
Исключение
ЗаписатьЛогСобытий("Ошибка при подписании: " + ОписаниеОшибки());
ВызватьИсключение ОписаниеОшибки();
КонецПопытки;
КонецПроцедуры
Проанализируем еще один критический момент: неинтерактивность сессии. Веб-сервисы работают в так называемой «Сессии 0», где невозможно отображение графических окон. Если ваш криптопровайдер (например, КриптоПро) при обращении к ключу настроен на обязательный запрос ПИН-кода через стандартное окно ОС, веб-сервис просто «зависнет» в ожидании ввода, который никто не увидит.
Чтобы избежать этого, мы должны либо передавать пароль в коде через свойство ПарольДоступаКЗакрытомуКлючу, либо настроить CSP на использование «сохраненных паролей» в реестре системы для конкретной учетной записи. Также убедитесь, что в настройках КриптоПро не стоит запрет на использование ключей в неинтерактивных сессиях.
Подводя итог, можно сказать, что решение проблемы всегда кроется в синхронизации учетной записи, под которой установлен сертификат, и учетной записи, под которой работает веб-сервер. Выяснив этот нюанс, вы сможете стабильно работать с криптографией в любых веб-сервисах 1С.