Czy „Trustworthy” warto zaufać? Bezpieczeństwo w SQL Server.
Nigdy nie bylem wielkim fanem tematów zwiazanych z bezpieczenstwem w SQL Server, ale historia o której chcialem Wam dzisiaj opowiedziec jest naprawde ciekawa i powinna „poruszyc” nawet najwiekszych ignorantów w tym obszarze.
SQL CLR + UNSAFE permission set = Trustworthy
Sprawa dotyczy ustawienia Trustworthy na poziomie bazy danych. Ustawienie czesto naduzywane przez programistów budujacych aplikacje z wykorzystaniem SQL CLR. Wlaczenie Trustworthy pozwala na uruchamianie procedur CLR z grupa uprawnien UNSAFE, czyli praktycznie bez kontroli i z pelnym dostepem do zasobów poza SQL Server.
Dlaczego programisci czesto z niego korzystaja? Bo jest latwo dostepne i upraszcza/przyspiesza proces pisania aplikacji a wiedza o ryzykach wynikajacych z tego ustawienia nie jest wystarczajaco rozpowszechniona.
No wlasnie, co oprócz mozliwosci uruchamiania „niebezpiecznych” CLR daje Trustworthy? Uzytkownikom w roli db_owner daje mozliwosc impersonacji na konto bedace wlascicielem bazy danych… Malo? Czasami bardzo duzo!
Dlaczego naduzywamy roli db_owner?
Zacznijmy od tego, ze nieuzasadnione przydzielanie roli db_owner w SQL Server jest bardzo powszechne. Wszedzie tam, gdzie pojawia sie potrzeba uruchamiania procedur skladowanych, zamiast nadawania uprawnien EXECUTE, na ogól wykorzystujemy role db_owner, dlaczego? Bo nie trzeba przydzielac uprawnien dla kazdej z procedur osobno… a przeciez w naszej bazie danych moze ich byc mnóstwo…
Z moich obserwacji wynika równiez, ze samo wdrozenie aplikacji/bazy danych na serwerze produkcyjnym bardzo czesto odbywa sie na koncie uzytkownika administrujacego danym serwerem, czyli sysadmin’a. Wówczas wlascicielem bazy danych (DBO) bedzie konto, w kontekscie którego wykonujemy wdrozenie. Czy to zle? Na pierwszy rzut oka niekoniecznie, ale kombinacja opisanych powyzej, dosc powszechnych praktyk moze doprowadzic do oplakanych w skutkach rezultatów.
Co z tego wynika?
Podsumujmy nasza hipotetyczna sytuacje (hipotetyczna, choc tak naprawde spotkalem sie z nia nie raz…):
- W naszej bazie danych wykorzystujemy ustawienie Trustworthy, na potrzeby uruchamiania UNSAFE CLR
- Uzytkownik aplikacyjny jest w naszej bazie w roli db_owner (dlatego, ze nie chcialo nam sie nadawac mu uprawnien do wszystkich procedur skladowanych z osobna)
- Wlascicielem bazy danych (dbo) jest login w roli sysadmin (administrator serwera odpowiedzialny za wdrozenie aplikacji)
No to teraz sie pobawmy…
Do przeprowadzenia demonstracji bedziemy potrzebowac dwa loginy. Dla przejrzystosci wykorzystamy loginy SQL’owe (choc dokladnie ten sam efekt osiagnac mozna z wykorzystaniem loginów opartych o konta domenowe). W tym celu zmieniam ustawienia uwierzytelniania na „mixed authentication” (pamietajcie, ze to nie jest „best practice”J). Loginy, które wykorzystamy do testów to:
- LoginWithSysadmin – reprezentujacy administratora serwera, przypisany do roli sysadmin na poziomie instancji SQL Server
- ApplicationLogin – reprezentujacy uzytkownika aplikacyjnego, za pomoca którego aplikacja dostaje sie do bazy danych. Jest on przypisany do roli db_owner w naszej bazie danych i nie posiada zadnych uprawnien na poziomie instancji SQL Server
Teraz mozemy zaczac dzialac… W pierwszym kroku nawiazujemy polaczenie z nasza instancja z wykorzystaniem LoginWithSysadmin, dla niedowiarków:
Login posiada juz uprawnienia sysadmin na poziomie instancji, oto dowód:
LoginWithSysadmin jest naszym administratorem serwera, to wlasnie on jest odpowiedzialny za wdrozenie aplikacji. Nie komplikujmy zbytnio scenariusza, po prostu stwórzmy pusta baze danych:
Domyslnie tworzona baza danych nie posiada wlaczonej opcji Trustworthy, to ustawienie z definicji jest wylaczone:
Wlaczmy zatem Trustworthy:
I sprawdzmy, czy rzeczywiscie sie udalo:
Wyglada na to, ze nasza baza danych jest juz przygotowana (wdrozenie sie powiodlo), mamy wlaczone Trustworthy, a wlascicielem jest nasz administrator (LoginWithSysadmin):
Teraz logujemy sie do naszego SQL Server z wykorzystaniem loginu aplikacyjnego:
Na poziomie instancji nie mamy zadnych uprawnien:
Ale w bazie TrustworthyDB jestesmy db_owner’em:
Jak na razie wszystko sie zgadza, na dowód braku uprawnien na poziomie instancji spróbujmy pokazac zaawansowane opcje z wykorzystaniem sp_configure:
Wyglada na to, ze nie mozna, czyli tak jak powinno byc… a teraz?
Uppss… no to kim ja wlasciwie teraz jestem?
…Jestem administratorem SQL’a, no to zróbmy cos fajnego:):
Teraz juz mam dostep do wiersza polecen. Dostep realizowany jest w kontekscie konta serwisowego SQL Server. Sprawdzmy, zatem jak konto sie nazywa:
I troche dodatkowych informacji:
A skoro juz wiemy, ze jest czlonkiem grupy lokalnych administratorów, to nie pozwólmy, zeby ktos o zlych zamiarach te luke wykorzystal:):
Pa pa!
Podsumowanie
Wlasciciel bazy danych z uprawnieniami sysadmin’a oraz wlaczona opcja Trustworthy to bardzo niebezpieczna kombinacja, z czego malo kto zdaje sobie sprawe. Jak dorzucimy do tego wysoko uprawnione konto serwisowe to mamy do czynienia z wyjatkowo niebezpieczna konfiguracja dajaca praktycznie nieograniczone mozliwosci potencjalnemu „wlamywaczowi”.
Sprawdzcie, czy Wasze bazy danych nie maja przypadkiem wlaczonej opcji Trustworthy… Trustworthy wcale nie warto ufac:)