В процессе администрирования прав доступа в конфигурациях на базе обычных форм, таких как 1С:Управление производственным предприятием 1.3 (УПП) или 1С:Управление торговлей 10.3 (УТ), специалисты часто сталкиваются с неприятным сюрпризом. Даже если у пользователя в его роли жестко ограничены права на интерактивное проведение, интерактивную отмену проведения или интерактивную пометку удаления документов, он все равно может выполнять эти операции. Происходит это в обход установленных запретов через стандартную общую форму Структура подчиненности (связанные документы).
В данной статье мы подробно разберем, почему возникает эта архитектурная уязвимость платформы «1С:Предприятие», проанализируем различные способы её устранения и приведем конкретные примеры программного кода для защиты вашей базы данных от несанкционированных действий пользователей.
Для того чтобы найти системное решение, нам необходимо понять, как платформа 1С разделяет права доступа на уровне метаданных. Все права на работу с объектами СУБД можно разделить на две категории:
Чтение, Добавление, Изменение, Удаление, Проведение, ОтменаПроведения. Эти права регулируют непосредственную возможность выполнения операций над базой данных на уровне СУБД. Если у пользователя отключено базовое право Отмена проведения, он физически не сможет распроводить документы ни одним из способов. Однако на практике эти базовые права почти всегда должны быть включены, иначе пользователи не смогут работать с документами в рамках своих бизнес-процессов.Интерактивное проведение, Интерактивная отмена проведения, Интерактивная пометка удаления, Интерактивное изменение проведенных и др. Эти права проверяются платформой 1С только тогда, когда пользователь совершает действие вручную непосредственно через стандартные интерфейсные механизмы (например, нажимая кнопку «Провести» или «Отмена проведения» в самой форме документа или в стандартном динамическом списке).Теперь проанализируем, что происходит, когда пользователь открывает форму Структура подчиненности и нажимает кнопки проведения или отмены проведения на верхней панели. Внутри обработчиков этих кнопок в коде общей формы написан программный вызов метода записи объекта:
ОбъектДокумента = СсылкаНаДокумент.ПолучитьОбъект();
ОбъектДокумента.Записать(РежимЗаписиДокумента.Проведение);
С точки зрения платформы «1С:Предприятие», данный вызов является программным, а не интерактивным. В этот момент интерактивные права пользователя (такие как Интерактивная отмена проведения) игнорируются. Система проверяет только базовые права на запись и проведение. Поскольку базовые права у пользователя есть, операция успешно выполняется. Ушлые пользователи быстро понимают эту особенность интерфейса и начинают втихую распроводить или помечать на удаление закрытые документы, минуя все установленные запреты в их формах.
Рассмотрим несколько вариантов решения этой проблемы — от простых локальных правок интерфейса до надежных системных ограничений на уровне базы данных.
Если мы хотим быстро закрыть эту уязвимость непосредственно в самой форме структуры подчиненности, нам потребуется доработать код обработчиков командных кнопок. Для этого мы можем принудительно вызвать метод платформы ВыполнитьПроверкуПравДоступа(), который позволяет программно инициировать проверку любого интерактивного права пользователя.
Рассмотрим пример кода, который необходимо встроить в обработчики кнопок проведения, отмены проведения и пометки удаления в модуле общей формы структуры подчиненности:
// Пример обработчика кнопки проведения документов на панели
Процедура ДействияФормыПровести(Кнопка)
ТекущиеДанные = ЭлементыФормы.ДеревоДокументов.ТекущиеДанные;
Если ТекущиеДанные = Неопределено Тогда
Возврат;
КонецЕсли;
СсылкаНаДокумент = ТекущиеДанные.Ссылка;
МетаданныеДокумента = СсылкаНаДокумент.Метаданные();
Попытка
// Принудительно проверяем право интерактивного проведения перед записью
ВыполнитьПроверкуПравДоступа("ИнтерактивноеПроведение", МетаданныеДокумента);
ОбъектДокумента = СсылкаНаДокумент.ПолучитьОбъект();
ОбъектДокумента.Записать(РежимЗаписиДокумента.Проведение, РежимПроведенияДокумента.Оперативный);
ТекущиеДанные.Проведен = Истина;
Сообщить("Документ успешно проведен: " + Строка(СсылкаНаДокумент));
Исключение
// Перехватываем ошибку отсутствия прав доступа
ТекстОшибки = ОписаниеОшибки();
Если Найти(ТекстОшибки, "недостаточно прав") <> 0 Тогда
Предупреждение("У вас недостаточно прав для выполнения интерактивного проведения этого документа!");
Иначе
Предупреждение("Не удалось провести документ. Ошибка: " + ТекстОшибки);
КонецЕсли;
КонецПопытки;
КонецПроцедуры
Аналогичную логику необходимо применить и для кнопок отмены проведения и пометки удаления, заменив проверяемое право на "ИнтерактивнаяОтменаПроведения" и "ИнтерактивнаяПометкаУдаления" соответственно.
Самый простой и быстрый способ закрыть уязвимость — полностью заблокировать или скрыть кнопки проведения, распроведения и удаления на панели инструментов общей формы структуры подчиненности. Это лишит пользователей возможности совершать какие-либо действия с документами из этого интерфейса, вынуждая их открывать сами документы.
Для реализации этого метода откроем общую форму структуры подчиненности в конфигураторе, перейдем в свойства панели инструментов (командной панели) и снимем флаги видимости или доступности для соответствующих кнопок. Также это можно сделать программно в процедуре ПриОткрытии формы:
Процедура ПриОткрытии()
// Блокируем доступ к кнопкам изменения состояния документов для обычных пользователей
Если Не РольДоступна("ПолныеПрава") Тогда
ЭлементыФормы.ДействияФормы.Кнопки.Провести.Доступность = Ложь;
ЭлементыФормы.ДействияФормы.Кнопки.ОтменитьПроведение.Доступность = Ложь;
ЭлементыФормы.ДействияФормы.Кнопки.УстановитьПометкуУдаления.Доступность = Ложь;
КонецЕсли;
КонецПроцедуры
Данный подход решает проблему локально, однако он не защищает базу данных, если продвинутый пользователь решит воспользоваться другими стандартными или внешними обработками (например, групповой обработкой справочников и документов).
Для того чтобы гарантированно защитить базу данных от обхода ограничений интерфейса, рекомендуется перенести логику проверок на уровень СУБД. Самым изящным и системным решением является использование механизма Подписок на события.
Создадим новую подписку на событие со следующими свойствами:
КонтрольПравПередЗаписьюДокументаДокументОбъект (выбираем типы документов, которые требуют контроля, либо все документы базы данных)ПередЗаписьюНиже представлен пример реализации программного кода в общем модуле для контроля отмены проведения и пометки на удаление документов:
Процедура КонтрольПравПередЗаписьюДокументаПередЗаписью(Источник, Отказ, РежимЗаписи, РежимПроведения) Экспорт
// Если запись выполняется под полными правами, то проверки опускаем
Если РольДоступна("ПолныеПрава") Тогда
Возврат;
КонецЕсли;
МетаданныеДокумента = Источник.Метаданные();
// 1. Проверяем попытку отмены проведения
Если РежимЗаписи = РежимЗаписиДокумента.Запись И Источник.Ссылка.Проведен И Не Источник.Проведен Тогда
// Документ был проведен, но теперь его пытаются записать как непроведенный
Если Не ПравоДоступа("ИнтерактивнаяОтменаПроведения", МетаданныеДокумента) Тогда
ОбщегоНазначенияКлиентСервер.СообщитьПользователю("У вас нет прав на отмену проведения документов данного типа!");
Отказ = Истина;
Возврат;
КонецЕсли;
КонецЕсли;
// 2. Проверяем явную отмену проведения
Если РежимЗаписи = РежимЗаписиДокумента.ОтменаПроведения Тогда
Если Не ПравоДоступа("ИнтерактивнаяОтменаПроведения", МетаданныеДокумента) Тогда
ОбщегоНазначенияКлиентСервер.СообщитьПользователю("У вас нет прав на отмену проведения документов данного типа!");
Отказ = Истина;
Возврат;
КонецЕсли;
КонецЕсли;
// 3. Проверяем установку пометки удаления
Если Источник.ПометкаУдаления И Не Источник.Ссылка.ПометкаУдаления Тогда
Если Не ПравоДоступа("ИнтерактивнаяПометкаУдаления", МетаданныеДокумента) Тогда
ОбщегоНазначенияКлиентСервер.СообщитьПользователю("У вас нет прав на пометку удаления документов данного типа!");
Отказ = Истина;
Возврат;
КонецЕсли;
КонецЕсли;
КонецПроцедуры
Этот метод является абсолютно надежным. Каким бы образом пользователь ни пытался изменить статус документа (через форму структуры подчиненности, групповую обработку или даже внешний СОМ-запрос), подписка на событие ПередЗаписью перехватит эту попытку на уровне сервера и заблокирует транзакцию, установив параметр Отказ = Истина.
Иногда возникает специфическая задача: пользователям нужно разрешить интерактивно отменять проведение документов, но исключительно из форм самих документов, полностью заблокировав эту возможность во всех списках, структуре подчиненности и обработках. В этом случае отлично помогает использование механизма ДополнительныеСвойства объекта.
Идея заключается в том, что при записи документа непосредственно из его формы мы помещаем специальный маркер во временную структуру свойств объекта. При записи в модуле документа или в подписке на события мы проверяем наличие этого маркера.
Разберем по шагам реализацию этого механизма:
Шаг 1. В модуле формы самого документа в обработчике события ПередЗаписью пропишем передачу уникального признака:
Процедура ПередЗаписью(Отказ, РежимЗаписи, РежимПроведения)
// Указываем, что запись инициирована непосредственно из формы документа
ЭтотОбъект.ДополнительныеСвойства.Вставить("ЗаписаноИзФормыДокумента", Истина);
КонецПроцедуры
Шаг 2. В подписке на событие ПередЗаписью или непосредственно в модуле объекта документа проанализируем наличие этого свойства при отмене проведения документа:
Процедура ПередЗаписью(Отказ, РежимЗаписи, РежимПроведения)
Если ОбменДанными.Загрузка Тогда
Возврат;
КонецЕсли;
// Проверяем отмену проведения обычным пользователем
Если (РежимЗаписи = РежимЗаписиДокумента.ОтменаПроведения
Или (РежимЗаписи = РежимЗаписиДокумента.Запись И Ссылка.Проведен И Не Проведен))
И Не РольДоступна("ПолныеПрава") Тогда
// Проверяем, был ли передан маркер из формы документа
ЗаписаноИзФормы = Неопределено;
Если Не ДополнительныеСвойства.Свойство("ЗаписаноИзФормыДокумента", ЗаписаноИзФормы) Или ЗаписаноИзФормы <> Истина Тогда
ВызватьИсключение "Отмена проведения данного документа разрешена только непосредственно из его формы!";
КонецЕсли;
КонецЕсли;
КонецПроцедуры
Этот способ позволяет гибко разграничить сценарии работы пользователей, защитив систему от массовых непродуманных изменений документов «в один клик» из групповых реестров и подчиненных связей.
В современных типовых решениях 1С (таких как ERP 2, Комплексная автоматизация 2, Управление торговлей 11), разработанных на базе Библиотеки стандартных подсистем (БСП), данная проблема учтена на уровне архитектуры самого шаблона конфигурации.
Отчет «Связанные документы» (современный аналог структуры подчиненности) перед выполнением групповых действий с объектами всегда принудительно вызывает специальные процедуры БСП, проверяющие права пользователя на интерактивные действия. Если у пользователя отсутствуют права на интерактивную отмену проведения, платформа выдаст стандартное системное предупреждение еще до начала выполнения программных транзакций записи. В устаревших решениях на обычных формах эту логику безопасности программисту приходится дорабатывать самостоятельно.
Подведем итог проведенного анализа. Чтобы гарантированно защитить информационную систему от обхода прав доступа через структуру подчиненности, выполните следующие действия:
ПередЗаписью. Это полностью исключит программный обход ограничений на уровне СУБД.