Как получить сертификат из личного хранилища при работе через веб-сервис 1С?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При разработке интеграций, требующих использования электронной подписи (например, для взаимодействия с ГИС МТ «Честный знак»), программисты 1С часто сталкиваются с проблемой: сертификат, который прекрасно виден в обычной сессии пользователя или во внешней обработке, категорически «не виден» коду, исполняемому внутри веб-сервиса. Рассмотрим подробнее, почему это происходит и как настроить систему для корректной работы с криптографией.

Суть проблемы: контекст выполнения веб-сервиса

Проанализируем ситуацию: веб-сервис 1С публикуется на веб-сервере (обычно Apache или IIS). Когда внешний клиент обращается к методу веб-сервиса, 1С выполняет этот код на стороне сервера. Проблема заключается в том, что по умолчанию службы веб-серверов запускаются от имени специальных системных учетных записей (например, LocalSystem, NetworkService или IUSR). У этих учетных записей есть свои собственные, зачастую пустые, хранилища сертификатов. Личное хранилище (Personal) того пользователя, под которым вы заходили в Windows и устанавливали сертификат, для этих системных служб просто недоступно.

Разберем типовой код, который может выдавать ошибку или возвращать Неопределено при запуске в контексте веб-сервиса:


// Попытка получения хранилища в серверном модуле веб-сервиса
МенеджерКриптографии = Новый МенеджерКриптографии("", "", 80); 
ХранилищеСертификатов = МенеджерКриптографии.ПолучитьХранилищеСертификатов(ТипХранилищаСертификатовКриптографии.ПерсональныеСертификаты);

// Поиск по отпечатку вернет Неопределено, если сертификат в хранилище другого пользователя
Сертификат = ХранилищеСертификатов.НайтиПоОтпечатку(ДвоичныеДанныеОтпечатка);

Решение №1: Настройка службы Apache

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

  1. Откроем оснастку «Службы» (services.msc).
  2. Найдем службу Apache2.4 (или вашу версию).
  3. Перейдем в свойства службы на вкладку «Вход в систему».
  4. Вместо «С системной учетной записью» выберем «С учетной записью» и укажем данные того пользователя ОС, под которым устанавливался сертификат в личное хранилище.
  5. Перезапустим службу.

После этих манипуляций метод МенеджерКриптографии.ПолучитьХранилищеСертификатов начнет обращаться к хранилищу именно этого пользователя, и сертификат будет успешно найден.

Решение №2: Особенности настройки IIS

При использовании Internet Information Services (IIS) ситуация несколько сложнее. Даже если вы настроите пул приложений на работу от имени нужного пользователя, этого может быть недостаточно. Выясним причину: IIS по умолчанию не загружает профиль пользователя полностью.

Проанализируем необходимые настройки в IIS:

  1. Откроем «Диспетчер служб IIS».
  2. Перейдем в раздел «Пулы приложений» и выберем пул, на котором опубликована база 1С.
  3. Нажмем «Дополнительные параметры».
  4. В разделе «Модель процесса» найдем параметр «Загрузить профиль пользователя» (Load User Profile) и установим его в значение True.
  5. В поле «Удостоверение» (Identity) укажите учетную запись пользователя, имеющего доступ к сертификату.

Если этого не сделать, система не увидит ветку реестра HKEY_CURRENT_USER, где и располагается информация о личном хранилище сертификатов, что приведет к ошибке открытия хранилища (часто с кодом 0x00000005 — доступ запрещен).

Решение №3: Управление правами на закрытый ключ

Нахождение сертификата в хранилище — это только первый этап. Для выполнения операции Подписать() серверу необходим доступ к закрытому ключу. Посмотрим, как предоставить этот доступ явно:

  1. Запустим оснастку управления сертификатами (certmgr.msc) под тем пользователем, чье хранилище используется.
  2. Найдем нужный сертификат в папке «Личное» -> «Сертификаты».
  3. Нажмем правую кнопку мыши, выберем «Все задачи» -> «Управление закрытыми ключами».
  4. Добавим в список пользователя, от имени которого запущен Apache или пул приложений IIS, и дадим ему права на «Чтение».

Решение №4: Использование хранилища локального компьютера

Если архитектура решения позволяет, рассмотрим вариант установки сертификата в хранилище Локального компьютера (Local Machine), а не текущего пользователя. Это позволит любому процессу на сервере (при наличии прав на ключи) обращаться к сертификату независимо от того, под каким пользователем запущен сервис.

При таком подходе в коде 1С необходимо использовать соответствующие параметры при инициализации хранилища. Однако помните, что при импорте сертификата в машинное хранилище необходимо убедиться, что криптопровайдер (например, КриптоПро CSP) корректно видит контейнер закрытого ключа в машинном контексте.

Пример кода для поиска и работы с сертификатом

Рассмотрим более развернутый пример функции, которая может быть использована в веб-сервисе для получения списка доступных сертификатов и последующего подписания. Обратите внимание на использование объекта МенеджерКриптографии.


&НаСервере
Функция ПолучитьСертификатПоОтпечатку(ОтпечатокСтрокой)
    
    // Инициализируем менеджер криптографии
    // Параметры зависят от установленного CSP (КриптоПро, ViPNet и т.д.)
    Менеджер = Новый МенеджерКриптографии("", "", 80); 
    
    // Получаем личное хранилище текущего пользователя процесса
    Хранилище = Менеджер.ПолучитьХранилищеСертификатов(ТипХранилищаСертификатовКриптографии.ПерсональныеСертификаты);
    
    // Преобразуем строковый отпечаток в двоичные данные
    ДвоичныеДанныеОтпечатка = ПолучитьДвоичныеДанныеИзГексагональнойСтроки(ОтпечатокСтрокой);
    
    Сертификат = Хранилище.НайтиПоОтпечатку(ДвоичныеДанныеОтпечатка);
    
    Если Сертификат = Неопределено Тогда
        ЗаписатьЛогСобытий("Сертификат с отпечатком " + ОтпечатокСтрокой + " не найден в хранилище.");
        Возврат Неопределено;
    КонецЕсли;
    
    Возврат Сертификат;
КонецФункции

&НаСервере
Процедура ПодписатьДанные(ПутьКФайлу, Отпечаток)
    
    Сертификат = ПолучитьСертификатПоОтпечатку(Отпечаток);
    Если Сертификат = Неопределено Тогда
        ВызватьИсключение "Ошибка: Сертификат не найден.";
    КонецЕсли;
    
    Менеджер = Новый МенеджерКриптографии("", "", 80);
    // Если контейнер защищен паролем, его нужно передать здесь
    Менеджер.ПарольДоступаКЗакрытомуКлючу = "ваш_пароль";
    
    ПутьКПодписанномуФайлу = ПутьКФайлу + ".sig";
    
    Попытка
        Менеджер.Подписать(ПутьКФайлу, ПутьКПодписанномуФайлу, Сертификат);
    Исключение
        ЗаписатьЛогСобытий("Ошибка при подписании: " + ОписаниеОшибки());
        ВызватьИсключение ОписаниеОшибки();
    КонецПопытки;
    
КонецПроцедуры

Важные замечания по интерактивности

Проанализируем еще один критический момент: неинтерактивность сессии. Веб-сервисы работают в так называемой «Сессии 0», где невозможно отображение графических окон. Если ваш криптопровайдер (например, КриптоПро) при обращении к ключу настроен на обязательный запрос ПИН-кода через стандартное окно ОС, веб-сервис просто «зависнет» в ожидании ввода, который никто не увидит.

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

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

← На главную