Czasami widzę pytania z pytaniem, jak bezpiecznie przechowywać hasła użytkownika do aplikacji internetowej (używając RDBMS, nie mówię o Facebooku ani Twitterze). Zazwyczaj odpowiedź brzmi: „zrób hasło, a następnie zahartuj je za pomocą silnego algorytmu, takiego jak TDES lub SHA512”.
Moje pytanie brzmi: jako użytkownik RDBMS, dlaczego miałbym w ogóle niepokoić się przechowywaniem haseł, ponieważ większość silników ma wbudowany mechanizm uwierzytelniania.
Na przykład, jeśli jakiś użytkownik X chce utworzyć hasło użytkownika do konta Y w mojej aplikacji internetowej, w jaki sposób wydaje się następujące zapytanie:
CREATE USER X WITH ENCRYPTED PASSWORD Y IN GROUP baseuser;
Następnie w mojej aplikacji użytkownik może otworzyć połączenie z bazą danych przy użyciu swoich poświadczeń i nie muszę się martwić zarządzaniem hasłami.
Widzę wiele zalet tej metody:
- Jeśli RDBMS zdecyduje, że algorytm szyfrowania musi zostać zmieniony, nie muszę niczego dotykać, aby zastosować aktualizacje zabezpieczeń;
- Łatwo jest mi zarządzać autoryzacjami użytkowników. Jeśli użytkownik zostanie awansowany do roli administratora, muszę tylko dodać użytkownika do odpowiedniej grupy;
- Zastrzyki SQL są teraz bez znaczenia, ponieważ zarządzam uprawnieniami, aby zezwalać dokładnie na to, co chcę, każdemu użytkownikowi w bazie danych (na przykład na forum takim jak SO, dodając nowe posty, odpowiadając na posty, komentując i edytując / usuwając własne pytania / odpowiedzi / komentarze);
- Konto użytkownika „anonimowe” może być używane do nieuwierzytelnionych połączeń z moją aplikacją;
- Każdy użytkownik jest właścicielem podanych przez siebie danych.
Ale praktycznie w każdym pytaniu, jakie widzę na ten temat, wydaje się, że panuje ogólna zgoda co do tego, że nie w ten sposób należy to robić. Moje pytanie brzmi: dlaczego?
Uwaga: Trzeci punkt jest dozwolony przez zasady w PostgreSQL i zasady bezpieczeństwa w Microsoft SQL Server. Zdaję sobie sprawę, że te koncepcje są nowicjuszami, ale zresztą, skoro już są, dlaczego opisana przeze mnie technika nie staje się standardowym sposobem obsługi kont użytkowników?
Odpowiedzi:
Ponieważ dla wielu aplikacji nie chcą indywidualnych kont użytkowników łączących się z bazą danych. Użytkownicy / hasła / prawa / uprawnienia są obsługiwane w warstwie aplikacji, a pojedyncze konto usługi dedykowanej służy do łączenia się z zapleczem bazy danych.
Jako DBA nie chcę zarządzać, na poziomie bazy danych, 10 000 aktywnych użytkowników jakiejś średniej wielkości publicznej aplikacji internetowej, a może ponad 2 milionami użytkowników nagle popularnej aplikacji.
W bardzo realnym sensie jest to różnica w filozofii między twórcami aplikacji a twórcami baz danych / DBA.
Wielu / większość twórców aplikacji nie chce przenosić odpowiedzialności za główne aspekty funkcjonalności aplikacji i / lub reguł biznesowych na warstwę bazy danych. Zamiast tego widzą bazę danych jako narzędzie do prostego przechowywania i pobierania danych.
W niektórych przypadkach może to być krótkowzroczność; wiele RDBMS ma niesamowite funkcje, które mogą znacznie ułatwić programistom życie (zabezpieczenia na poziomie wierszy, indeksy kolumnowe, przechowywanie strumienia plików itp.).
Ale niektóre z tych fajniejszych funkcji są dostępne tylko w nowszych wersjach, a organizacje nie zawsze szybko aktualizują istniejące środowiska (patrz ten wykres z 2014 roku ).
A w innych przypadkach preferowane jest zarządzanie tymi rzeczami w warstwie aplikacji (i nie tylko w przypadku przenośności platformy bazy danych, szczerze myślę, że roszczenie jest przesadzone).
źródło
W tym momencie linia podziału staje się trochę puszysta, ale uważam, że użytkownicy i uprawnienia na poziomie bazy danych są częścią schematu, a nie częścią danych, i ogólnie aplikacje nie mają miejsca na modyfikowanie schematu (istnieją, jak zawsze wyjątki od tej reguły).
Wolę nie dawać aplikacjom uprawnień, których potrzebują do zarządzania obiektami schematu (loginy, użytkownicy i uprawnienia), ponieważ nowi użytkownicy są potrzebni, a starzy odchodzą, ponieważ jeśli aplikacja zostanie zaatakowana przez hakera, osoba atakująca ma wówczas dostęp do tych uprawnień. ułatwiając włamanie do bazy danych, aby otworzyć dalej. W MS SQL Server, chyba że używasz w pełni zawartych baz danych, loginy są obiektami na poziomie serwera, więc musisz przekazywać uprawnienia poza bazę danych jednej aplikacji, co czyni to jeszcze bardziej ryzykownym.
Co więcej, nawet jeśli masz konta dla poszczególnych aplikacji na poziomie bazy danych, nadal potrzebujesz kont użytkowników na poziomie aplikacji do obsługi nieuwierzytelnionych żądań - tj. Jeśli aplikacja potrzebuje informacji z bazy danych, zanim użytkownik aplikacji pomyślnie się uwierzytelni (np. wyświetlać informacje o statusie na ekranie powitalnym / logowania?).
Również jeśli celem jest przenośność między aparatami bazy danych (być może Twoja aplikacja chce być w stanie działać zarówno na mysql, jak i postgres?), Wówczas Twoje aplikacje będą musiały wyodrębnić funkcje zarządzania użytkownikami / logowaniem dla każdego silnika, ponieważ nie są między nimi standardem - jeśli podejmujesz ten wysiłek, możesz równie dobrze samodzielnie wprowadzić hasła i uzyskać pożądane opcje zarządzania, zamiast akceptować najniższy wspólny zestaw funkcji, jaki oferują silniki.
źródło
Ponowne pytanie
Najprostsza odpowiedź brzmi: musisz to zrobić. Nadal przechowujesz hasła w alternatywnej metodzie. Wystarczy użyć wbudowanego systemu bazy danych do zarządzania pamięcią. Więc twoja metoda jest tak dobra, jak twoja baza danych. To może być lepsze niż cokolwiek, co możesz zrobić inaczej, ale nie unikniesz przechowywania. Naprawdę po prostu unika się przechowywania kodu.
To też może nie być lepsze. Jeśli skompromituję bazę danych i otrzymam kopie plików, będę mógł uzyskać bezpośredni dostęp do tabel. Dlatego nie ma sensu używać genialnego systemu zarządzania hasłami. Ponieważ jeśli ktoś może uzyskać dostęp do tabeli na poziomie systemu zawierającej hasła lub hasła mieszane, może również uzyskać bezpośredni dostęp do plików. Po co zawracać sobie głowę łamaniem haseł, gdy masz już dane? Nie jest tak, że możesz łatwo szyfrować dane. Każdy użytkownik musi mieć do niego dostęp. Szyfrowanie na poziomie użytkownika nie będzie działać tak dobrze.
Ale tak naprawdę wydaje się, że pytasz
Bezpieczeństwo
Ignorując możliwość napisania bezpieczniejszej wersji, inni sugerowali kilka powodów. Generalnie się zgadzam. Ale jest jeszcze coś, o czym nikt jeszcze nie wspomniał. Narażasz bezpieczeństwo swojej bazy danych.
W tym systemie każdy użytkownik aplikacji ma użytkownika bazy danych i hasło. Jasne, to ograniczony użytkownik, ale nadal to użytkownik, który może połączyć się z bazą danych. Nawet jeśli używasz zabezpieczeń na poziomie wiersza, nadal pozwalasz użytkownikom końcowym poznać informacje o połączeniu z bazą danych. Jeśli kiedykolwiek istnieje exploit, w którym użytkownik może uzyskać dostęp nawet na poziomie tabeli, otworzyłeś bazę danych do ataku. Niektóre exploity wykraczają poza dostęp administratora.
W warstwach cebuli zabezpieczającej normalny system to:
W tym systemie:
Straciliśmy cały poziom bezpieczeństwa aplikacji. I dobrowolnie zrezygnowaliśmy z części warstwy bazy danych. Potrzebujemy tylko dwóch exploitów:
Jeśli możemy zrobić te dwie rzeczy, mamy dostęp do bazy danych. Więc przechodzimy od trzech warstw do dwóch. (Trzecia warstwa w normalnym systemie polega na tym, że potrzebny jest prawidłowy użytkownik, aby połączyć się z bazą danych.)
Będziesz dużo zarządzał tymi kontami. Co jeśli popełnisz błąd? Zamiast ograniczać użytkownika X tylko do niektórych wierszy, dajesz im dostęp do krytycznej tabeli. Tego rodzaju czynności zwykle wykonuje się ręcznie, a jest ich tylko kilka, więc można je łatwo skontrolować. Ale w twoim systemie możesz robić tysiące, miliony, a nawet miliardy kont użytkowników, każde z własnym osobliwym dostępem.
W tym sensie, czy system bazy danych skaluje się do milionów czy miliardów użytkowników? Jeśli tak, to co z liczbą reguł? Jeśli każdy użytkownik podejmie sto lub więcej zasad dotyczących tego, co może, a czego nie może uzyskać dostępu, czy to może zwiększyć się do miliarda użytkowników? Bierzesz zwykle mały system i robisz go na dużą skalę. To niekoniecznie zadziała. W miarę wzrostu możesz napotkać ograniczenia systemowe.
źródło
To, co opisujesz, obsłuży uwierzytelnianie, ale nie autoryzację (do jakich danych użytkownik może uzyskać dostęp) lub tylko w najprostszym przypadku użycia.
Aby kontynuować na przykładzie zmiany stosu: Jak sprawić, aby usunięty post był widoczny tylko dla użytkowników z wysokim przedstawicielem? Więc do reguł dostępu nadal potrzebujesz logiki w kodzie. Zamiast dzielić logikę dostępu między regułami bazy danych i regułami dostępu do aplikacji, większość programistów woli mieć je wszystkie w tym samym miejscu.
Będziesz także potrzebować tabeli do przechowywania informacji o użytkowniku: użytkownik to nie tylko nazwa użytkownika + hasło. Ma e-maila, reputację i tak dalej. Dlatego nadal potrzebujesz tabeli użytkowników, która musi być zsynchronizowana z tabelą użytkowników bazy danych, pod warunkiem, że masz do niej dostęp.
W swoim rozwiązaniu możesz po prostu pominąć kolumnę z hasłami, która nie jest tak trudna do wypełnienia: istnieją dobre biblioteki i dokumentacja dotycząca obsługi / hashowania haseł.
Inna kwestia: jak utworzyłbyś pulę połączeń? Znam tylko jdbc (java <-> db) i musisz podać nazwę użytkownika + hasło, aby uzyskać połączenie, które możesz następnie połączyć.
Pomyślałem o kilku innych kwestiach, które będą trudniejsze / bardziej skomplikowane do wdrożenia niż w ustalony sposób:
źródło
CREATE POLICY deleted_posts_high_rep ON posts FOR SELECT TO baseuser USING ((SELECT rep FROM users WHERE name = current_user()) > 10000)
odpowiedzi na twoje pierwsze pytanie. Nigdy nie mówiłem, że nie potrzebuję już tabeli użytkowników, a zapewnienie synchronizacji z tabelą użytkowników db jest nieco trudne, ale możliwe. Głównym punktem omawianej techniki jest bezpieczeństwo. Jeśli chodzi o pulę połączeń, pracuję z OCaml i muszę powiedzieć, że nie rozumiem, dlaczego potrzebuję puli połączeń. Obecnie używam mapy skrótu kojarzącej wartości plików cookie z funkcjami 0-Jeszcze jedna uwaga: wiele aplikacji internetowych [1] umożliwia rejestrację i utworzenie konta użytkownika online za pośrednictwem samej aplikacji. Co oznacza, że Twój anonimowy użytkownik (który powinien mieć najmniejsze uprawnienia, jakie można założyć) musi mieć prawa do tworzenia użytkowników i przyznawania uprawnień!
OK, może być możliwe ograniczenie uprawnień, które może on nadać, i dać użytkownikom wyższego poziomu więcej opcji przyznania (choć nie wiem, że tak jest - nie jest to często „przyznanie uprawnień” pojedynczym uprawnieniem). Ale nadal oznacza to umieszczenie w Internecie czegoś z uprawnieniami do przyznawania grantu, aby każdy mógł się włamać. Jestem prawie pewien, że moja DBA nie polubiłaby mnie, gdybym to zrobił :)
Wiem, że na jednym poziomie problem ten i tak istnieje, ale masz warstwy obrony, szczególnie w przypadku usuwania danych, jeśli nie pozwalasz aplikacji internetowej na zarządzanie użytkownikami bazy danych.
Zapobiegnie to również wykorzystaniu połączenia DB lub puli DB.
[1] Większość powiedziałbym, ale nie dane, aby to poprzeć
źródło