Sam nie wiem z czego to wynika, ale uzytkownicy proponuja czasami nieco abstrakcyjne rozwiazania zwiazane z ustawieniem uprawnien do bazy danych.
W tym przypadku klient chcial aby uzytkownicy bazy danych mogli pracowac na poziomie uprawnien db_owner, ale z jednym malym haczykiem. Uzytkownicy nie powinni moc usunac bazy danych. Dlaczego uwazam, ze zyczenie jest nieco abstrakcyjne? Otoz db_owner to bardzo wysokie uprawnienie, wiec zlosliwy uzytkownik moze:
- pousuwac tabele
- zmodyfikowac procedury
- zabrac uprawnienia innym uzytkownikom
- itp.
Wydaje sie ze lepszym rozwiazaniem byloby wybranie tylko tych uprawnien, ktore sa rzeczywiscie potrzebne i nadanie ich do roli bazy danych. Potem uzytkownikow wystarczy przypisywac do tej roli. Byloby bezpieczniej.
No ale… usuniecie bazy danych jak opisano w https://docs.microsoft.com/en-us/sql/t-sql/statements/drop-database-transact-sql?view=sql-server-2017 moze byc wykonane tylko w 3 przypadkach:
- uzytkownik ma upranienie ALTER ANY DATABASE
- uzytkownik ma uprawnienie CONTROL
- uzytkownik jest db_ownerem
Requires the CONTROL permission on the database, or ALTER ANY DATABASE permission, or membership in the db_owner fixed database role.
Skoro u nas uzytkownik jest db_ownerem, to mozna mu zabrac uprawnienie do kasowania bazy tylko na 2 sposoby:
- deny alter any database to user_name
- deny control on database::db_name to user_name
Pierwsza z tych metod powoduje, ze uzytkownik nie moze np tworzyc tabel w bazie danych, dodawac nowych uzytkownikow, wiec generalnie do niczego taki db_owner sie nie nadaje
Druga z tych metod uniemozliwia korzystanie z bazy danych, wiec ogolnie odpowiedz na pytanie czy taka konfiguracje mozna stworzyc brzmi „nie”.
Jest jednak szansa na zbudowanie obejscia tego problemu. Od czego mamy DDL trigger na poziomie serwera?
Mozna stworzyc nowa role na serwerze np. deny_drop i przypisac do niej uzytkownikow, ktorzy maja miec zakaz usuwania baz danych:
USE [master] GO CREATE SERVER ROLE [deny_drop] GO ALTER SERVER ROLE [deny_drop] ADD MEMBER [user_name] GO
Nastepnie mozna stworzyc DDL trigger, ktory jesli zauwazy, ze kasowanie bazy danych jest wykonywane przez uzytkownika nalezacego do danej roli, to wykona rollback:
CREATE TRIGGER DenyDatabaseDrop ON ALL SERVER FOR DROP_DATABASE AS DECLARE @db_name SYSNAME, @event_data XML SET @event_data = EVENTDATA() SELECT @db_name=@event_data.value('data(/EVENT_INSTANCE/DatabaseName)[1]', 'SYSNAME') IF @db_name IN ('restricted_database_name') AND (IS_SRVROLEMEMBER('deny_drop') = 1) BEGIN PRINT 'To drop this database contact your DBA' ROLLBACK; END GO ENABLE TRIGGER [DenyDatabaseDrop] ON ALL SERVER
No i w sumie gotowe. Jesli uzytkownik jest w roli deny_drop i usunie baze , ktorej nazwa jest podana w wyrazeniu IF powyzej, to wykona sie rollback i baza nie bedzie usunieta.
Oczywiscie to jest obejscie problemu. Nie jest to czysty srodek security. Popranie, nadajac uprawnienia nalezy to zrobic z glowa!