Верить нельзя никому, даже себе!
...
Против лома нет приема!
...
Для любой хитрой сущности первого рода
есть сущность второго рода с винтом!
….
(три источника, три составных части
развития любой системы безопасности).
Описание проблемы:
Часто случается так, что в базе работают пользователи с полными правами, но имеют при этом «кривоватые руки». Иногда это бывают влиятельные «ответственные» лица, имеющие достаточно влияния, чтобы под благовидным предлогом «отжать» себе полные права. При этом отобрать у них полные права назад бывает нереально. Иногда это бывает из-за определенной неразберихи в системе прав, либо при начальном этапе внедрения, либо обусловленной сложившимися бизнес-процессами.
Не всегда такие пользователи ответственно относятся к своей работе. И хорошо при этом, что они по незнанию не могут натворить ничего плохого в базе. Хуже, когда кто-то из них узнает о потенциально опасных инструментах (вроде групповых обработок) и начинает жать на «Выполнить», не осознавая в полной мере последствий своих действий.
Как правило, полный доступ таким пользователям нужен для того, чтобы, не обращаясь ни к кому, что-нибудь провести, записать в базе или выполнить какую-нибудь обработку не опасного характера. Поэтому для восстановления порядка и гармонии в базе достаточно бывает ограничить доступ к фиксированному списку объектов конфигурации, имеющих критическое значение.
Предлагаемое решение:
К сожалению, в подтверждение к сказанному в эпиграфе к статье, полного и окончательного решения обсуждаемой проблемы нет. Можно предлагать лишь меры частного характера, действующие при определенных условиях и до определенной степени хитрости «сущностей первого рода».
Например, решить озвученную задачу можно методом «умножения»:
1) Создадим второй набор «полных» прав и обзовем его, допустим, роль “SA” (super-administrator).
2) В какой-нибудь удобный общий серверный модуль добавим экспортную функцию
для усиленной проверки полного доступа к базе вроде следующей:
// усиленная проверка полного доступа к базе
Функция ДоступПолный_Проверить(UserName = "", НеУчитыватьSA = Ложь) Экспорт
//для 8.1 функцию нужно поместить в привилегированный модуль
УстановитьПривилегированныйРежим(Истина); //и убрать эту строку!
Если ПустаяСтрока(UserName) Тогда
User = Неопределено;
Иначе
User = ПользователиИнформационнойБазы.НайтиПоИмени(UserName);
КонецЕсли;
ДоступПолный = ПравоДоступа("Администрирование",Метаданные,User)
И ПравоДоступа("ОбновлениеКонфигурацииБазыДанных",Метаданные,User)
И ПравоДоступа("МонопольныйРежим",Метаданные,User)
И ПравоДоступа("ИнтерактивноеОткрытиеВнешнихОбработок",Метаданные,User);
Если НеУчитыватьSA <> Истина Тогда
Если Метаданные.Роли.Найти("SA") <> Неопределено Тогда
Если User = Неопределено Тогда
ДоступПолный = ДоступПолный И РольДоступна("SA");
Иначе
ДоступПолный = ДоступПолный И User.Роли.Содержит(Метаданные.Роли["SA"]);
КонецЕсли;
КонецЕсли;
КонецЕсли;
Если Метаданные.Роли.Найти("ПолныеПрава") <> Неопределено Тогда
Если User = Неопределено Тогда
ДоступПолный = ДоступПолный И РольДоступна("ПолныеПрава");
Иначе
ДоступПолный = ДоступПолный И User.Роли.Содержит(Метаданные.Роли["ПолныеПрава"]);
КонецЕсли;
КонецЕсли;
Возврат ДоступПолный;
КонецФункции
3) С помощью указанной выше функции перед открытием форм или выполнением команд, имеющих критическое значение, проверяем наличие супер-прав и отказываем в доступе при их отсутствии.
Узкие места предлагаемого решения:
Помимо необходимости внесения изменения в конфигурацию базы, основным недостатком предлагаемого решения является то, что пользователь с «простыми» полными правами может сам себе назначить роль “SA”.
Для этого в 1С есть две стандартных возможности:
- Непосредственно в конфигураторе;
- Типовые средства управления правами в пользовательском режиме;
Допустим, средствами администрирования операционной системы (через публикацию нужных ярлыков) в конфигуратор 1С запрещено заходить, кому не следует. Тогда нам остается запретить доступ к роли “SA” через средства управления правами типовой конфигурации.
Для реализации этого запрета нужно исключить набор прав “SA” из списков ролей, предлагаемых для выбора типовыми средствами управления правами. Также нужно исключить обработку роли “SA” в тех местах кода конфигурации, где фактически изменяются права пользователей (чтобы не сбросить доступ к роли “SA”, установленный в конфигураторе).
Сделать это достаточно просто, конкретная реализация зависит от конфигурации базы.
Пример реализации запрета для конфигураций «родственных» УТ-11.1 приведен ниже.
Но это еще не все:
Пользователь с «простыми» полными правами может запустить внешнюю обработку, например, какую-нибудь консоль кода,
и с ее помощью назначить себе нужные права, выполнив простенький код:
ЯЯ = ПользователиИнформационнойБазы.ТекущийПользователь();
//ЯЯ = ПользователиИнформационнойБазы.НайтиПоИмени("Вася");
SA = Метаданные.Роли.SA;
Если НЕ ЯЯ.Роли.Содержит(SA) Тогда
ЯЯ.Роли.Добавить(SA);
ЯЯ.Записать();
КонецЕсли;
Чтобы заткнуть эту дырку, потребуется подрезать «простые» полные права:
- Запретить для "простых" полных прав запуск внешних отчетов и обработо;
- Также запретить публикацию внешних отчетов и обработок в справочнике «Дополнительные отчеты и обработки»;
Но и это еще не все (и продолжать можно до бесконечности):
Как верно подсказывает Stim213 в //infostart.ru/public/182849/, продвинутый ушлый пользователь может с помощью блокнота вставить указанный выше код в нужное место файла выгрузки данных (например, в текст кода обработчика “Перед загрузкой данных”). А затем при загрузке данных из файла в информационную базу получить себе нужные права.
Работающий пример реализации запрета доступа к роли “SA”:
Конфигурация «Управление торговлей, релиз 11.1.9.70» (версия БСП: 2.2.3.44).
Права пользователям задаются в профилях безопасности.
Для запрета доступа к роли “SA” типовыми средствами нужно сделать несколько вставок (выделены авторскими комментариями //+yuraos ) в следующие места исполняемого кода конфигурации:
Общий модуль «ПользователиСлужебный»:
Процедура ПодготовитьДеревоРолей(Знач Коллекция, Знач СкрытьРольПолныеПрава, Знач ПоказатьТолькоВыбранныеРоли, КоллекцияРолей)
Индекс = Коллекция.Количество()-1;
Пока Индекс >= 0 Цикл
Строка = Коллекция[Индекс];
ПодготовитьДеревоРолей(Строка.Строки, СкрытьРольПолныеПрава, ПоказатьТолькоВыбранныеРоли, КоллекцияРолей);
Если Строка.ЭтоРоль Тогда
Если СкрытьРольПолныеПрава
И ( ВРег(Строка.Имя) = ВРег("ПолныеПрава")
ИЛИ ВРег(Строка.Имя) = ВРег("АдминистраторСистемы")) Тогда
Коллекция.Удалить(Индекс);
Иначе
//+yuraos
Если СкрытьРольПолныеПрава И (ВРег(СокрЛП(Строка.Имя)) = "SA") Тогда
// роль SA выставляем персонально каждому в конфигураторе
Коллекция.Удалить(Индекс);
Индекс = Индекс-1;
Продолжить;
КонецЕсли;
//+yuraos
Строка.НомерКартинки = 7;
Строка.Пометка = КоллекцияРолей.НайтиСтроки(
Новый Структура("Роль", Строка.Имя)).Количество() > 0;
Если ПоказатьТолькоВыбранныеРоли И НЕ Строка.Пометка Тогда
Коллекция.Удалить(Индекс);
КонецЕсли;
КонецЕсли;
Иначе
Если Строка.Строки.Количество() = 0 Тогда
Коллекция.Удалить(Индекс);
Иначе
Строка.НомерКартинки = 6;
Строка.Пометка = Строка.Строки.НайтиСтроки(
Новый Структура("Пометка", Ложь)).Количество() = 0;
КонецЕсли;
КонецЕсли;
Индекс = Индекс-1;
КонецЦикла;
КонецПроцедуры
Процедура ОбновитьРолиВнешнихПользователей(Знач МассивВнешнихПользователей = Неопределено) Экспорт
//*****
Выборка = Запрос.Выполнить().Выбрать();
ПользовательИБ = Неопределено;
Пока Выборка.Следующий() Цикл
//+yuraos
Если ВРег(СокрЛП(Выборка.Роль)) = "SA" Тогда
// роль SA выставляем персонально каждому в конфигураторе
Продолжить;
КонецЕсли;
//+yuraos
Если ЗначениеЗаполнено(Выборка.Роль) Тогда
ПользовательИБ.Роли.Добавить(Метаданные.Роли[Выборка.Роль]);
Продолжить;
КонецЕсли;
Если ПользовательИБ <> Неопределено Тогда
ПользовательИБ.Записать();
КонецЕсли;
ПользовательИБ = ПользователиИнформационнойБазы.НайтиПоУникальномуИдентификатор(ИдентификаторыПользователейИБ[Выборка.ВнешнийПользователь]);
ПользовательИБ.Роли.Очистить();
КонецЦикла;
Если ПользовательИБ <> Неопределено Тогда
ПользовательИБ.Записать();
КонецЕсли;
//*****
КонецПроцедуры
Общий модуль «УправлениеДоступомСлужебный»:
Процедура ОбновитьРолиПользователейИБ(ОбновляемыеПользователиИБ, ПарольПользователяСервиса)
Для каждого КлючИЗначение Из ОбновляемыеПользователиИБ Цикл
РолиДляДобавления = КлючИЗначение.Значение.РолиДляДобавления;
РолиДляУдаления = КлючИЗначение.Значение.РолиДляУдаления;
ПользовательИБ = КлючИЗначение.Значение.ПользовательИБ;
ПользовательСсылка = КлючИЗначение.Значение.ПользовательСсылка;
БылиПолныеПрава = ПользовательИБ.Роли.Содержит(Метаданные.Роли.ПолныеПрава);
Для каждого КлючИЗначение Из РолиДляДобавления Цикл
//+yuraos
Если ВРег(СокрЛП(КлючИЗначение.Ключ)) = "SA" Тогда
// роль SA выставляем персонально каждому в конфигураторе
Продолжить;
КонецЕсли;
//+yuraos
ПользовательИБ.Роли.Добавить(Метаданные.Роли[КлючИЗначение.Ключ]);
КонецЦикла;
Для каждого КлючИЗначение Из РолиДляУдаления Цикл
//+yuraos
Если ВРег(СокрЛП(КлючИЗначение.Ключ)) = "SA" Тогда
// роль SA выставляем персонально каждому в конфигураторе
Продолжить;
КонецЕсли;
//+yuraos
ПользовательИБ.Роли.Удалить(Метаданные.Роли[КлючИЗначение.Ключ]);
КонецЦикла;
ЗаписатьПользователяПриОбновленииРолей(ПользовательСсылка, ПользовательИБ, БылиПолныеПрава, ПарольПользователяСервиса);
КонецЦикла;
КонецПроцедуры