Способы определить привилегированный режим: код, отладчик, журналы

· 9 мин

Содержание

Самый быстрый способ — вызвать в коде функцию ПривилегированныйРежим(). Она вернёт Истина, если текущий участок исполняется с отключённой проверкой прав и без ограничений доступа на уровне записей (RLS). Функция доступна на сервере, в фоновом задании и во внешнем соединении.

Но спрашивают об этом по-разному. Иногда нужно убедиться прямо из своей процедуры, иногда — выяснить, почему пользователь без прав увидел «чужие» данные, а иногда — разобраться, в каком режиме отработал проблемный участок типовой конфигурации. Под каждую задачу — свой инструмент: встроенная функция, отладчик, технологический журнал, анализ ролей.

Ниже — платформа 1С:Предприятие 8.3 (интерфейс «Такси»), клиент-серверный и файловый варианты. Привилегированный режим — механизм серверный, поэтому большая часть проверок выполняется на стороне сервера.

Что отключает привилегированный режим и зачем его контролировать

Привилегированный режим — это участок кода, внутри которого платформа не проверяет права пользователя и не применяет ограничения доступа к данным (RLS). Код обращается к любым объектам так, будто у текущего пользователя полные права.

Его включают осознанно: служебные операции (запись регистров, проведение, доступ к справочникам настроек), которые пользователь по правам делать не должен, но которые нужны в рамках бизнес-логики. Проблема возникает, когда режим включили и забыли выключить или включили шире, чем нужно, — тогда пользователь получает доступ к данным, которые от него закрыты.

Чтобы понять эффект, представьте типичное ограничение RLS: менеджер видит документы только своей организации — остальные скрыты условием в роли. Пока код идёт обычно, платформа подставляет это условие в каждый запрос к документам. Как только участок входит в привилегированный режим, условие перестаёт действовать, и тот же запрос вернёт документы всех организаций. Именно поэтому важно знать, в каком режиме отработал конкретный блок: от этого зависит, что увидел пользователь.

Поэтому проверять режим приходится в двух ситуациях:

  • 🔍 разработка — убедиться, что служебный блок идёт привилегированно, а пользовательский — нет;
  • 🛡️ разбор инцидента — понять, почему проверка прав не сработала и где код «поднял» себе полномочия.

Включается режим вызовом УстановитьПривилегированныйРежим(Истина), выключается — УстановитьПривилегированныйРежим(Ложь). Эти вызовы вложенные: сколько раз включили, столько же нужно выключить.

Функция ПривилегированныйРежим() — проверка прямо в коде

Базовый инструмент — две встроенные функции глобального контекста.

ПривилегированныйРежим() возвращает булево: Истина — код сейчас в привилегированном режиме, Ложь — в обычном. Параметров нет.

Если ПривилегированныйРежим() Тогда
    Сообщить("Код идёт привилегированно: права и RLS отключены");
Иначе
    Сообщить("Обычный режим: проверка прав действует");
КонецЕсли;

КоличествоПривилегированныхРежимов() возвращает число — сколько раз режим включался вложенно и ещё не выключен. Ноль означает обычный режим, значение больше нуля — глубину вложенности. Это удобно, когда нужно убедиться, что включений и выключений поровну.

Сообщить(СтрШаблон("Глубина привилегированного режима: %1",
    КоличествоПривилегированныхРежимов()));

Чтобы не словить «протекший» режим из-за исключения, включение и выключение оборачивают в Попытка … КонецПопытки:

УстановитьПривилегированныйРежим(Истина);
Попытка
    // служебные операции без проверки прав
    ЗаписатьСлужебныеДанные();
Исключение
    УстановитьПривилегированныйРежим(Ложь);
    ВызватьИсключение;
КонецПопытки;
УстановитьПривилегированныйРежим(Ложь);

УстановитьПривилегированныйРежим() работает только на сервере и во внешнем соединении. На тонком и веб-клиенте этот вызов недоступен и приведёт к ошибке компиляции. А вот ПривилегированныйРежим() вызвать можно где угодно — на клиенте она просто вернёт Ложь.

Если нужно разово «подсветить» режим в чужом коде, не меняя логику, добавьте временную строку с записью в журнал регистрации — к ней вернёмся ниже.

Проверка в отладчике без правки кода

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

Порядок действий для клиент-серверной базы:

  1. В конфигураторе откройте Отладка → Подключение и подключитесь к серверному предмету отладки (нужно, чтобы на сервере был разрешён отладчик — параметр задаётся при запуске службы кластера).
  2. Поставьте точку останова (F9) на нужной строке модуля.
  3. Выполните в базе действие, которое приводит к этой строке. Отладчик остановится.
  4. Нажмите Shift+F9 (Вычислить выражение) и введите ПривилегированныйРежим(). В поле результата увидите Истина или Ложь.

Тот же результат можно держать перед глазами постоянно: добавьте ПривилегированныйРежим() и КоличествоПривилегированныхРежимов() в окно Табло — значения будут пересчитываться на каждом шаге отладки.

Отладчик отвечает на вопрос «в каком режиме строка исполняется сейчас», а не «включался ли режим когда-то». Чтобы увидеть момент включения, ставьте точку останова прямо на строку УстановитьПривилегированныйРежим(Истина) в подозрительном модуле.

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

Если точка останова не срабатывает на сервере, проверьте, что отладка по протоколу разрешена при запуске агента сервера, а в свойствах информационной базы кластера блокировка регламентных заданий и сеансов не мешает запуску. Без разрешённой серверной отладки вычислить ПривилегированныйРежим() на сервере не получится — останется только путь с логированием в код.

Привилегированные общие модули и роли

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

Поэтому первый шаг при разборе — открыть в конфигураторе свойства общего модуля, через который прошёл вызов, и посмотреть флаг Привилегированный. Если он стоит — весь код модуля идёт с отключёнными правами, и ПривилегированныйРежим() внутри него вернёт Истина.

Как режим связан с ролевой моделью:

  • роли задают права (чтение, добавление, проведение) и ограничения доступа к данным (RLS) — именно их привилегированный режим и обходит;
  • RLS применяется ко всем пользователям, у которых назначена роль с ограничениями, — и обычным, и с широкими правами; снимает его только привилегированный режим;
  • обход через режим — это не повышение прав конкретного пользователя, а доверие к коду разработчика. Пользователь выполняет написанную процедуру, а не получает новые полномочия интерактивно.

Флаг Привилегированный у общего модуля действует на сервере. Клиентские процедуры этого модуля привилегированными не становятся — на клиенте механизма просто нет.

Отсюда практический вывод: если пользователь без прав видит закрытые данные, ищите либо явный УстановитьПривилегированныйРежим(Истина), либо привилегированный общий модуль в цепочке вызова.

Отдельно стоит внешнее соединение (COM-подключение к базе): код в нём, как и на сервере, может переключать режим, и ПривилегированныйРежим() там тоже работает. Это важно при разборе интеграций: обработка, подключающаяся к базе внешним соединением, способна войти в привилегированный режим так же, как серверный код.

Фоновые и регламентные задания: где смотреть режим

Код фонового задания исполняется на сервере, поэтому там доступны обе функции и можно вызвать УстановитьПривилегированныйРежим. Само по себе задание привилегированным не становится — оно работает с правами того пользователя, под которым запущено (для регламентного задания этот пользователь задаётся в его настройках).

Проверить режим внутри задания интерактивным отладчиком неудобно — выполнение идёт без пользователя. Надёжнее — логирование в журнал регистрации из самого кода задания:

ЗаписьЖурналаРегистрации(
    "ПроверкаРежима",
    УровеньЖурналаРегистрации.Информация,
    ,
    ,
    СтрШаблон("Привилегированный режим: %1, глубина: %2",
        ПривилегированныйРежим(),
        КоличествоПривилегированныхРежимов()));

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

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

Журналы сервера: где искать следы режима

Технологический журнал не хранит отдельного признака «привилегированный режим» — такого поля в нём нет. Его роль другая: показать, какой модуль и метод отработал и в какой последовательности шли вызовы. Зная цепочку, вы находите подозрительный участок, а сам режим подтверждаете уже в коде или отладчике.

Журнал включается файлом logcfg.xml в каталоге conf рабочего процесса. Полезны события серверных вызовов и исключений — по ним видно имена модулей и методов в стеке. Дальше открываете найденный общий модуль и смотрите флаг Привилегированный или ищете в нём явное включение режима.

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

Журнал регистрации тоже не содержит колонки «режим». Но он помогает выявить последствия привилегированного режима: если пользователь выполнил действие, которого по своим правам делать не может (например, запись в закрытый от него регистр), значит, код в этот момент шёл привилегированно.

Как использовать:

  • отфильтруйте журнал по пользователю и периоду инцидента (Администрирование → Журнал регистрации или аналогичный раздел конфигурации, плюс фильтр по пользователю);
  • сопоставьте выполненные действия с его ролями: расхождение указывает на привилегированный код в цепочке;
  • для точной фиксации добавьте в подозрительный код запись в журнал через ЗаписьЖурналаРегистрации() с текущим значением ПривилегированныйРежим(), как в примере выше;
  • если инцидент разовый и воспроизвести его тяжело, выгрузите журнал за нужный интервал в файл и анализируйте выгрузку отдельно, не нагружая рабочую базу фильтрацией большого периода.

Этого достаточно, чтобы от «что-то пошло не так» перейти к конкретному модулю. Дальше в конфигураторе остаётся открыть этот модуль и проверить две вещи: свойство Привилегированный у общего модуля и наличие явных переключений режима в теле метода. Так косвенный след из журнала превращается в точный ответ, в каком режиме шёл код.

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

Какой способ выбрать

Что именно нужно выяснить про привилегированный режим?

Частые ошибки при работе с привилегированным режимом

  • Включили режим и не выключили. Без пары УстановитьПривилегированныйРежим(Ложь) весь дальнейший код в этом вызове идёт с отключёнными правами. Контролируйте баланс через КоличествоПривилегированныхРежимов() — после вашего блока она должна вернуться к исходному значению.
  • Режим «протёк» через исключение. Если между включением и выключением возникла ошибка, выключение не выполнится. Оборачивайте блок в Попытка … КонецПопытки и выключайте режим в секции Исключение.
  • Ждут привилегированности на клиенте. Флаг общего модуля и УстановитьПривилегированныйРежим работают на сервере. Клиентский код привилегированным не становится.
  • Путают режим с полными правами. Пользователь с полными правами всё равно под действием RLS своих ролей, пока код не вошёл в привилегированный режим. Это разные механизмы.
  • Ищут режим в журналах напрямую. Ни журнал регистрации, ни технологический журнал не помечают привилегированный режим отдельным флагом. Они указывают на код, а режим подтверждается функцией или отладчиком.

Частые вопросы

Чем `ПривилегированныйРежим()` отличается от `УстановитьПривилегированныйРежим()`?
Первая только читает текущее состояние и возвращает булево. Вторая переключает режим: Истина — включить, Ложь — выключить. Переключение доступно лишь на сервере и во внешнем соединении.
Можно ли проверить режим на клиенте?
Вызвать ПривилегированныйРежим() на клиенте можно, но она вернёт Ложь: клиентский код привилегированным не бывает. Включить режим на клиенте нельзя.
Как понять, что общий модуль привилегированный?
Откройте его свойства в конфигураторе и посмотрите флаг «Привилегированный». Если он установлен, все экспортные методы модуля на сервере выполняются с отключённой проверкой прав.
Привилегированный режим обходит и права, и RLS?
Да. Внутри режима платформа не проверяет права доступа и не применяет ограничения доступа к данным на уровне записей.
Почему пользователь без прав увидел закрытые данные?
Скорее всего, данные ему отдал код, работавший привилегированно, — через явное включение режима или привилегированный общий модуль. Найдите этот участок в цепочке вызова.