Как защититься от инъекции произвольного кода при использовании метода Выполнить() в 1С?

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

Динамическое исполнение программного кода с помощью метода Выполнить() является одним из наиболее рискованных механизмов платформы 1С:Предприятие. Попытка подставить непроверенную пользовательскую строку или имя переменной напрямую в исполняемый контекст часто приводит к уязвимостям выполнения произвольного кода (Code Injection). Разберем, почему простые фильтрации символов не обеспечивают безопасность и как правильно организовать работу с динамическими объектами.

Проблема: иллюзия безопасности «черных списков» символов

Рассмотрим типовую ситуацию, когда разработчик пытается динамически обратиться к переменной с таблицей значений, предварительно очистив входную строку от точки с запятой:


ИмяНужнойТаблицы = ОчиститьОтТочкиЗапятой(ИмяНужнойТаблицы);
Выполнить("ВременнаяТаблицаДляСохранения = " + ИмяНужнойТаблицы + ".Скопировать();");
СохранитьТаблицуКудаНадо(ВременнаяТаблицаДляСохранения);

На первый взгляд кажется, что удаление символа ; предотвратит добавление дополнительных выражений. Однако подход с использованием «черных списков» (удаление точки с запятой, круглых скобок и других спецсимволов) фундаментально ненадежен. Выясним причину, по которой злоумышленник всё равно сможет внедрить исполняемый код.

Векторы обхода примитивной фильтрации

Проанализируем примеры конструкций, с помощью которых внедренный код успешно исполняется даже при отсутствии явной точки с запятой во входной строке:

  1. Динамическая генерация разделителей через функции платформы: Злоумышленник может передать вызов функции Символ() с кодом 59 (символ точки с запятой). Например, конструкция вида Выполнить("Выполнить(""Сообщить(1)"" + Символ(59) + ""Сообщить(2)"")"); полностью обходит текстовую очистку входной строки от символа ;.
  2. Использование функций с побочными эффектами: Если строка допускает точки или круглые скобки, можно вызвать любую глобальную функцию или метод объекта, возвращающий значение нужного типа, параллельно выполнив вредоносное действие.
  3. Переносы строк и спецсимволы: Синтаксический анализатор платформы может интерпретировать перевод строки или символы форматирования как разделение инструкций в зависимости от контекста.
  4. Унаследованный контекст и права: Метод Выполнить() выполняется в той же области видимости и с теми же правами, что и вызывающий программный код. Если процедура запущена в привилегированном режиме или на сервере без контроля прав, внедренный код получает полные права администратора информационной базы, что позволяет выполнить удаление данных, чтение защищенных сведений или вызовы внешних систем.

Альтернатива 1: Использование коллекций вместо динамического кода

Наиболее надежный и правильный архитектурный подход — полностью отказаться от метода Выполнить(). Для динамического обращения к объектам по строковому имени следует использовать коллекцию Структура или Соответствие.

Посмотрим на пример безопасной реализации:


// Формируем контейнер с таблицами
КонтейнерТаблиц = Новый Структура;
КонтейнерТаблиц.Вставить("ТаблицаТовары", ИсходнаяТаблицаТовары);
КонтейнерТаблиц.Вставить("ТаблицаУслуги", ИсходнаяТаблицаУслуги);

// Безопасное получение и обработка таблицы
ИсходнаяТЗ = Неопределено;
Если КонтейнерТаблиц.Свойство(ИмяНужнойТаблицы, ИсходнаяТЗ) И ТипЗнч(ИсходнаяТЗ) = Тип("ТаблицаЗначений") Тогда
    ВременнаяТаблицаДляСохранения = ИсходнаяТЗ.Скопировать();
    СохранитьТаблицуКудаНадо(ВременнаяТаблицаДляСохранения);
Иначе
    ВызватьИсключение "Указана недопустимая таблица данных.";
КонецЕсли;

В этом случае значение переменной ИмяНужнойТаблицы выступает исключительно строковым ключом поиска в структуре. Какое бы вредоносное содержимое ни было передано в строку, оно физически не может быть исполнено платформой.

Альтернатива 2: Проверка по «белому списку» (Whitelist)

Если набор возможных имен таблиц заранее известен и ограничен, применим строгий контроль по списку разрешенных значений:


РазрешенныеТаблицы = Новый Массив;
РазрешенныеТаблицы.Добавить("ТаблицаТовары");
РазрешенныеТаблицы.Добавить("ТаблицаУслуги");

Если РазрешенныеТаблицы.Найти(ИмяНужнойТаблицы) = Неопределено Тогда
    ВызватьИсключение "Попытка обращения к неразрешенной переменной.";
КонецЕсли;

Альтернатива 3: Строгая валидация идентификатора 1С

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

Разберем функцию проверки корректности имени идентификатора:


Функция ЭтоКорректныйИдентификатор1С(Знач ИмяПеременной)
    
    ИмяПеременной = СокрЛП(ИмяПеременной);
    
    Если ПустаяСтрока(ИмяПеременной) Тогда
        Возврат Ложь;
    КонецЕсли;
    
    ДопустимыеСимволы = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZабвгдеёжзийклмнопрстуфхцчшщъыьэюяАБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ_0123456789";
    Цифры = "0123456789";
    
    // Первый символ не может быть цифрой
    ПервыйСимвол = Сред(ИмяПеременной, 1, 1);
    Если СтрНайти(Цифры, ПервыйСимвол) > 0 Тогда
        Возврат Ложь;
    КонецЕсли;
    
    // Проверка всех символов строки
    ДлинаСтроки = СтрДлина(ИмяПеременной);
    Для Позиция = 1 По ДлинаСтроки Цикл
        Символ = Сред(ИмяПеременной, Позиция, 1);
        Если СтрНайти(ДопустимыеСимволы, Символ) = 0 Тогда
            Возврат Ложь;
        КонецЕсли;
    КонецЦикла;
    
    Возврат Истина;
    
КонецФункции

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

Дополнительные системные механизмы безопасности

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

  1. Безопасный режим платформы: При вызове внешних обработок или непроверенного кода используйте процедуру УстановитьБезопасныйРежим(Истина). В безопасном режиме платформа блокирует запуск привилегированного режима, выполнение внешних приложений через операционную систему, вызовы COM-объектов и внешних компонент, а также ограничивает прямой доступ к файловой системе.
  2. Профили безопасности: В клиент-серверном варианте базы данных администратор может настроить профили безопасности кластера 1С:Предприятия. Это позволяет аппаратно ограничить возможности серверных процессов по выходу во внешнюю сеть и обращению к дисковой подсистеме сервера.
← На главную