Почему COM-объект WinSCP работает под пользователем, но выдает ошибку в регламентном задании 1С?

Программист 1С v8.3 (Обычные формы) Торговля и дистрибуция
← На главную

Часто разработчики 1С сталкиваются с ситуацией, когда код, прекрасно работающий при интерактивном запуске от имени пользователя, начинает сбоить при выполнении в фоновом или регламентном задании. Особенно часто это проявляется при работе с внешними компонентами и COM-объектами, например, с популярной библиотекой WinSCP для работы с SFTP/SCP. Рассмотрим типичный случай: код для подключения к SFTP-серверу работает в пользовательском сеансе, но в регламентном задании падает с ошибкой на строке получения отпечатка ключа сервера.

Пример проблемного кода:


Попытка
    session = Новый COMОбъект("WinSCP.Session"); 
    sessionOptions = Новый COMОбъект("WinSCP.SessionOptions"); 
    sessionOptions.HostName = "roadstore.avito.ru";
    sessionOptions.UserName = "pan-remont";
    sessionOptions.Password = "bhtyjrr6AzDh";
    sessionOptions.PortNumber = 522;

    // ↓ Ошибка возникает именно на этой строке в фоновом режиме
    fingerprint = session.ScanFingerprint(sessionOptions,"SHA-256");      
    sessionOptions.SshHostKeyFingerprint = fingerprint;

    session.Open(sessionOptions);
Исключение
    // В журнал регистрации попадает ошибка:
    // {ОбщийМодуль...}: Ошибка при вызове метода контекста (ScanFingerprint):
    // Произошла исключительная ситуация (WinSCPnet): WinSCP.SessionRemoteException
    ЗаписьЖурналаРегистрации("МояПодсистема", УровеньЖурналаРегистрации.Ошибка,,, ОписаниеОшибки());
КонецПопытки;

Давайте разберемся, почему так происходит и как это исправить.

Анализ проблемы: два разных мира — интерактивный сеанс и фоновое задание

Ключ к пониманию проблемы лежит в контексте выполнения кода. Это два совершенно разных сценария:

  1. Интерактивный запуск. Когда вы запускаете обработку вручную, даже на сервере через RDP, код выполняется от имени вашей учетной записи операционной системы. Эта учетная запись имеет свой профиль (папки в C:\Users\ИмяПользователя), свои настройки сети, свои права доступа, сохраненные сертификаты и ключи.
  2. Регламентное задание. Когда тот же код запускается сервером 1С в фоновом режиме, он выполняется от имени учетной записи, под которой запущена служба «Агент сервера 1С:Предприятия». Чаще всего по умолчанию это системные учетные записи (Local System, Network Service) или специально созданный пользователь (например, USR1CV8).

Именно эта разница в правах и окружении и является корнем зла. Системная учетная запись, в отличие от пользовательской, может не иметь:

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

Пути решения проблемы

Рассмотрим несколько способов решения, от самого правильного и надежного до элегантных обходных маневров.

Решение 1: Настройка учетной записи службы сервера 1С (рекомендуемый)

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

Разберем по шагам:

  1. Создайте пользователя в Windows. В оснастке «Управление компьютером» создайте нового локального пользователя, например, USR1CV8. Задайте ему надежный пароль и установите флаг «срок действия пароля не ограничен».
  2. Предоставьте необходимые права. Этот пользователь должен иметь право на «Вход в качестве службы» (настраивается в локальных политиках безопасности) и права на чтение/запись в каталоги, которые использует сервер 1С (папка с установленной платформой, каталог временных файлов, папки с логами).
  3. Создайте профиль пользователя. Это важный шаг! Войдите на сервер в систему под этой новой учетной записью хотя бы один раз. При первом входе Windows создаст для нее пользовательский профиль (папку C:\Users\USR1CV8). Это решит потенциальные проблемы с COM-объектами, которые ожидают наличие такого профиля.
  4. Смените пользователя службы. Откройте оснастку «Службы» (services.msc), найдите службу «Агент сервера 1С:Предприятия 8.3», откройте ее свойства. На вкладке «Вход в систему» выберите опцию «С указанной учетной записью», введите имя созданного пользователя (например, .\USR1CV8) и его пароль.
  5. Перезапустите службу. После применения настроек перезапустите службу агента сервера 1С.

После этих действий все фоновые и регламентные задания будут выполняться в контексте пользователя USR1CV8, у которого есть свой профиль и которому можно гибко настроить права доступа к сети и файловой системе. Вероятность успешного выполнения кода с COM-объектом WinSCP приблизится к 100%.

Решение 2: Жестко прописать отпечаток ключа (более безопасный код)

Если изменять настройки службы сервера 1С нет возможности или желания, можно пойти другим путем — модифицировать код так, чтобы он не вызывал проблемный метод ScanFingerprint. Этот метод выполняет динамическое сканирование ключа, что удобно, но не всегда необходимо и не всегда безопасно.

Гораздо более надежный подход — заранее узнать отпечаток ключа хоста и жестко прописать его в коде. Это не только решает нашу проблему, но и повышает безопасность, защищая от атаки «человек посередине» (Man-in-the-Middle).

Как это сделать:

  1. Получите отпечаток ключа. Самый простой способ — подключиться к нужному серверу (roadstore.avito.ru) с помощью графического клиента WinSCP с любой машины. При первом подключении программа покажет диалоговое окно с предупреждением о неизвестном ключе и отобразит его отпечаток (fingerprint). Скопируйте его.
  2. Измените код 1С. Закомментируйте или удалите строку с вызовом ScanFingerprint и напрямую присвойте полученный отпечаток свойству SshHostKeyFingerprint.

Посмотрим на пример измененного кода:


session = Новый COMОбъект("WinSCP.Session"); 
sessionOptions = Новый COMОбъект("WinSCP.SessionOptions"); 
sessionOptions.HostName = "roadstore.avito.ru";
sessionOptions.UserName = "pan-remont";
sessionOptions.Password = "bhtyjrr6AzDh";
sessionOptions.PortNumber = 522;
// Укажем протокол явно, это хорошая практика
sessionOptions.Protocol = 1; // 0=SFTP (по-умолчанию в старых версиях), 1=SCP, 2=FTP, 3=SFTP
// Уточните протокол у администратора удаленного сервера. Для SFTP нужно значение 3.
// Либо sessionOptions.Protocol = Протокол.Sftp, если есть доступ к перечислению WinSCP.

// Строку с динамическим сканированием убираем
// fingerprint = session.ScanFingerprint(sessionOptions,"SHA-256");

// Вместо этого жестко прописываем заранее известный отпечаток
// Важно! Укажите полный формат, который показывает WinSCP, включая "sha256;"
sessionOptions.SshHostKeyFingerprint = "sha256;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=";

session.Open(sessionOptions);

Этот способ позволяет полностью обойти проблемное место и сделать код более предсказуемым и безопасным.

Решение 3: Глубокая диагностика через логи WinSCP

Если предыдущие методы не помогли или вы хотите докопаться до истинной причины, можно включить детальное логирование сессии самого WinSCP. COM-объект позволяет указать путь к файлу, куда будут записываться все шаги подключения.

Как включить логирование:

Добавьте в код строку для установки свойства SessionLogPath перед вызовом метода Open или ScanFingerprint.


Попытка
    session = Новый COMОбъект("WinSCP.Session"); 
    
    // Включаем логирование
    // Убедитесь, что у пользователя службы сервера 1С есть права на запись в этот каталог!
    session.SessionLogPath = "C:\1C_Logs\winscp_log.txt";

    sessionOptions = Новый COMОбъект("WinSCP.SessionOptions");
    // ... дальнейшие настройки
    
    fingerprint = session.ScanFingerprint(sessionOptions,"SHA-256");
    // ...
Исключение
    // ...
КонецПопытки;

После того как регламентное задание отработает с ошибкой, откройте файл C:\1C_Logs\winscp_log.txt. В нем вы найдете подробный отчет о попытке подключения. Скорее всего, последние строки перед ошибкой явно укажут на причину: Network error: Connection timed out (проблема с сетью/брандмауэром), Access denied (проблема с правами) или что-то еще, что поможет точно диагностировать и устранить неисправность.

← На главную