Po co w ogóle przechowywać hasła użytkowników?

10

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?

Fabian Pijcke
źródło
2
Komentarze nie są przeznaczone do rozszerzonej dyskusji; ta rozmowa została przeniesiona do czatu .
Paul White 9
Nawiasem mówiąc, zwykła odpowiedź jest zła. Powinieneś zasolić hasło, a następnie haszować je powolnym algorytmem, takim jak bcrypt lub argon2.
Tgr

Odpowiedzi:

27

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).

BradC
źródło
2
Istnieje „święta wojna”, niezależnie od tego, czy logika biznesowa idzie w aplikacji, czy w bazie danych. Jeśli zbudowałeś aplikację, w której cała logika biznesowa (w szczególności bezpieczeństwo) znajduje się w bazie danych (przy użyciu procedur przechowywanych, widoków itp.), Może istnieć argument, aby użyć mechanizmów bezpieczeństwa bazy danych, ponieważ nikt nie może połączyć się bezpośrednio i obejść twojego bezpieczeństwo. Całkowicie się zgadzam, że powinieneś unikać „przebudowywania” mechanizmu bezpieczeństwa (tj. Loginu / hasła) w niestandardowej tabeli. Po co to robić, skoro masz już zabezpieczenia active directory / O365.
Nick.McDermaid
1
@ Nick.McDermaid Lubię mieć pewność, że logicznie łączę logikę biznesową między DB a aplikacją, aby wyeliminować potencjał przyszłych deweloperów do uzyskania cholernej wskazówki, co się dzieje, pomaga mi też zachować bezpieczeństwo pracy, ponieważ nikt nie jest szalony wystarczająco, aby chcieć nim zarządzać.
Der Kommissar
Rzuć tam usługę internetową i serwer aplikacji tomcat, a możesz pracować dla IBM
Nick.McDermaid
8

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.

David Spillett
źródło
1
Ok, więc „aplikacja nie powinna zmieniać schematu” jest moim zdaniem pierwszym dobrym punktem w stosunku do techniki, którą sugeruję. Jednak konto anonimowe zdolne do tworzenia nowych użytkowników musi mieć możliwość tworzenia nowych użytkowników z najbardziej podstawowym dostępem. Tylko administratorzy mogą promować użytkowników i upuszczać użytkowników, co, jak sądzę, jest potrzebne w aplikacjach :-) Ogólne dane są widoczne dla anonimowego użytkownika, więc to połączenie może być użyte w przypadku treści, w których uwierzytelnianie nie jest potrzebne. Przenośność jest również dobrym punktem, ale myślę, że polecenia użytkownika są teraz częścią standardu (nie jestem pewien, nie było to lata temu)
Fabian Pijcke
Nawiasem mówiąc, dzięki temu ustawieniu, jeśli haker uzyska dostęp do bazy danych jako anonimowy użytkownik, będzie mógł utworzyć tyle użytkowników, ile chce, ale nie jest to kwestia bezpieczeństwa, mógłby z pewnością nadmuchać bazę danych za pomocą jednego z utworzone konta, co byłoby denerwujące, ale znowu nie ma problemu z bezpieczeństwem (a i tak mógłby to zrobić przy użyciu standardowego interfejsu, byłoby to jednak znacznie wolniejsze: p)
Fabian Pijcke
3
Zgadzam się, że z punktu widzenia bezpieczeństwa użytkownicy korzystający z bazy danych byliby lepsi. Jest to jednak w zasadzie niemożliwe do zarządzania np. W sklepach internetowych, w których może być 50 milionów zarejestrowanych użytkowników. Każdy musiałby być użytkownikiem bazy danych. Plus: zwykle nie działa dobrze w aplikacjach internetowych korzystających z puli połączeń.
a_horse_w_no_name
6

Ponowne pytanie

Po co w ogóle przechowywać hasła użytkowników?

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

Po co używać schematu uwierzytelniania na poziomie aplikacji, jeśli baza danych już go ma?

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:

  • Baza danych, która umożliwia połączenia tylko z niektórych komputerów.
  • Baza danych zezwala na połączenia tylko jako pewne kombinacje użytkownika / hasła.
  • Serwery z uprawnieniami do bazy danych, które umożliwiają połączenia z aplikacji.
  • Aplikacje są uruchamiane na serwerze.
  • Aplikacje mają informacje o połączeniu z bazą danych z ograniczonymi uprawnieniami.
  • Aplikacje uwierzytelniają użytkowników przed umożliwieniem im modyfikacji bazy danych (z wyjątkiem ewentualnego tworzenia nowych kont).

W tym systemie:

  • Użytkownicy końcowi znają kombinacje użytkowników i haseł, które będą działać na bazie danych, co prawda z bardzo niskimi uprawnieniami.
  • Musi tylko składać się z serwera lub udawać, że jest autoryzowanym serwerem.

Straciliśmy cały poziom bezpieczeństwa aplikacji. I dobrowolnie zrezygnowaliśmy z części warstwy bazy danych. Potrzebujemy tylko dwóch exploitów:

  1. Sfałszuj lub narażaj autoryzowany serwer.
  2. Zwiększ dostęp do konta z ograniczonymi uprawnieniami.

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.

mdfst13
źródło
5

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:

  • obsługa odzyskiwania hasła
  • 2 lata po pierwszym wdrożeniu menedżer produktu prosi o dodanie obsługi schematu oauth lub zezwolenie na uwierzytelnianie podwójnego współczynnika
Thierry
źródło
Coś w rodzaju 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-
aryjskimi
5
Pula połączeń została zaimplementowana w celu zwiększenia wydajności: dzięki nim nie trzeba ustanawiać połączenia dla każdego żądania użytkownika (dzięki czemu oszczędzasz cpu / io / opóźnienie po utworzeniu łącza tcp + całe połączenie i wymiana autoryzacji z bazą danych). Jeśli chodzi o definicję zasad: baza danych będzie stale sprawdzać prawo dostępu przy każdym dostępie do danych, nawet jeśli już je sprawdziłeś. Również „odmowa lub zakaz dostępu” to nie to samo, co „OK, brak wyniku”. Nie jestem pewien, czy ochroniarze wolą wersję OK.
Thierry
3
Fabian, pula połączeń jest fundamentalna w jakiejkolwiek skali, to naprawdę domyślna opcja, której nawet nie wziąłbyś pod uwagę. Oto kilka testów porównawczych, które pozwolą Ci zorientować się, jak ważne jest: 600 - krotny wzrost wydajności dzięki puli połączeń ( vladmihalcea.com/2014/04/17/the-anatomy-of-connection-pooling ) i ponad 4000-krotny wzrost wydajności dzięki pula połączeń ( progress.com/tutorials/jdbc/… ). To kilka rzędów wielkości różnicy, nie jest to „miłe mieć”, bez tego aplikacje zatrzymałyby się.
Ivan McA
1
Ciekawe liczby I rzeczywiście, nigdy nie widziałem aplikacji, która nie korzysta z pul połączeń. Ale nie wiedziałem (i nie spodziewam się), że spowodują tak duże przyspieszenie. Innym aspektem związanym z pulą połączeń jest kontrola zasobów: dzięki nim ogromny wzrost liczby klientów próbujących połączyć się naraz spowoduje spowolnienie działania aplikacji, ale nie wpłynie to znacząco na bazę danych (jeśli pula jest dobrze skonfigurowana) .
Thierry
Ok, właśnie szukałem więcej informacji o pulach połączeń i zgadzam się, że jest to bardzo ważny punkt, gdy tylko strona będzie musiała obsłużyć ponad sto połączeń na sekundę, co nie jest tak wysokie. Wygląda na to, że każde połączenie w PostgreSQL zjada około 10 MB pamięci RAM! Nigdy nie myślałem, że to tyle.
Fabian Pijcke
1

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ć

Adam
źródło