Co sprawia, że format przechowywania jest odzyskiwalny
Cztery formy przechowywania, posortowane według odzyskiwalności:
| Format | Odzyskiwalny? | Przykład | Metoda Odzyskiwania |
|--------|-------------|---------|-----------------|
| W formie tekstowej | Tak | password: hunter2 | Odczytaj plik |
| Base64 | Tak | cGFzc3dvcmQ= | base64 --decode |
| Zaszyfrowane odwracalnie (AES) | Tak | ENC[AES256:...] | Zdekryptuj za pomocą klucza |
| Haszowanie jedną stroną (bcrypt) | Nie | $2b$12$... | Nie można odwrócić; musisz próbować siłą |
W formie tekstowej, base64 i zaszyfrowane odwracalnie: wszystko odzyskiwalne. Jedna kopia bazy danych danych dostarcza atakującemu wszystkich haseł w formie jawnej dla wszystkich użytkowników naraz. Jedna napaść; pełne ujawnienie.
Przykład Mailmana 2.x
Mailman 2.x (menedżer list e-mail GNU): przechowywał hasła subskrybentów w formie tekstowej. E-mail powiadomienia o hasłach miesięcznie: wysyłał wszystkim subskrybentom ich hasło w formie jawnej. Dwukrotny wada, obie MOAD-0006:
1. Przechowywanie: w formie tekstowej w bazie listy. Kompromitacja serwera ujawnia wszystkie hasła subskrybentów.
2. Wysyłanie: miesięczny e-mail wysyła hasło w formie tekstowej za pomocą SMTP do serwera e-mail subskrybenta. E-mail podróżuje w formie tekstowej przez kilka hali SMTP.
Zespół Mailmana zaprojektował oba zachowania. Odzyskiwanie było cechą: subskrybenci mogli odzyskać zapomniane hasła. Nazwa Szklane Bezpieczne pochodzi od tego: bezpiecznik zawiera klucze w widocznej formie. Każdy, kto dotrze do bezpiecznika, może przeczytać zawartość naraz.
Zasada Już Skradniętego
Klucz przechowywany w formie odzyskiwalnej to klucz już skradziony. Atakujący jeszcze nie przybył. Napaść jeszcze nie miała miejsca. Ale architektura gwarantuje: gdy nastąpi napaść, wszystkie klucze upadną naraz. Nie ma napaści w izolacji; każdy klucz przechowywany w formie odzyskiwalnej przechodzi do atakującego w tej samej operacji.
MOAD-0006 vs MOAD-0004
MOAD-0004 (Zaszyfrowane Tajemnice): klucze zapisywane do dzienników nieumyślnie. Zapis dziennika nie był celem; był to efekt uboczny włączenia logowania nagłówków do debugowania.
MOAD-0006 (Bezpieczne Szklane): klucze przechowywane w formie odzyskiwalnej przez projekt. Odzyskiwanie było celem. Funkcja powiadomienia o hasłach wymagała przechowywania hasła. Funkcja wyświetlania hasła wymagała przechowywania go. Zobowiązanie architektoniczne do odzyskiwania utworzyło wadę.
Odgrywka jednej linijki: MOAD-0004 wprowadza dane logowania do logów przez przypadek; MOAD-0006 przechowuje dane logowania w formie odzyskiwalnej celowo. Naprawy działają na różnych poziomach.
Strukturalne vs Przypadkowe
Architektoniczna różnica między MOAD-0006 a MOAD-0004 determinuje strategię naprawy. Nieumyślne wpisanie do logów: naprawa warstwy serializacji. Zaprojektowane do odzyskiwania magazynowanie: przekonstruuj funkcję, która wymagała odzyskiwania.
Dlaczego bcrypt działa
Funkcja hash jednokierunkowa przyjmuje hasło i produkuje stałą długość digestu. Otrzymując digest, nie można odzyskać pierwotnego hasła. Nie 'trudno do odzyskania': niemożliwe do odwrócenia. Funkcja działa w jednym kierunku tylko.
Trzy właściwości wymagane dla magazynowania kredentiali:
1. Jednower. Otrzymując hash(hasło), żaden algorytm nie odzyskuje hasło szybciej niż przez siłę burzącą. bcrypt, scrypt i argon2 spełniają tę właściwość.
2. Sól. Losowy wartość dodawana do hasła przed haszowaniem. To samo hasło, różna sól, różny hash. Cel: pokonanie tablic jedwabnych (precomputed hash słownika). Bez soli: atakujący oblicza hash('password123') raz i sprawdza wszystkich 1 milion użytkowników jednocześnie. Z solą: każdy użytkownik ma unikalny hash nawet dla tego samego hasła.
3. Slow by design. bcrypt akceptuje czynnik pracy. Wyższy czynnik pracy: więcej iteracji, więcej czasu obliczeń na próbę haszowania. Logowanie: 300ms na jedno haszowanie. Akceptowalne. Szturm na hasła: 300ms na próbę. Na 1 miliard prób: 9,5 lat na jedno hasło. Niedopuszczalne dla atakującego. Powolność: cecha, a nie wada.
import bcrypt
# Przechowywanie: jednostronny hash z solą
def store_password(plaintext: str) -> bytes:
return bcrypt.hashpw(plaintext.encode(), bcrypt.gensalt(rounds=12))
# Weryfikacja: haszowanie kandydackiego hasła i porównanie składników
def verify_password(plaintext: str, stored_hash: bytes) -> bool:
return bcrypt.checkpw(plaintext.encode(), stored_hash)
# NIGDY nie przechowywane: hasło w postaci plaintext
# NIGDY nie odzyskiwane: plaintext z hasza
# Resetowanie hasła, a nie powtórzenie hasła
Zrównoważony wybór
Hashowanie jednostronne sprawia, że odzyskanie hasła jest niemożliwe. Użytkownik, który zapomniał swojego hasła, nie może go otrzymać z powrotem. Nie można wysłać e-maila z powtórzeniem hasła. Doświadczenie użytkownika zmienia się: 'zapomniałeś hasła? Zresetuj je.' Nie jest to degradacja: granica bezpieczeństwa. System, który nie może odzyskać hasła, nie może też ujawnić hasła.
Napad na bazę danych, która wyjawia hasła bcrypt: wszystkie hasła widoczne, żadnych haseł nie ma. Atakujący musi próbować siłą każdego hasła osobno, z 300ms na próbę, z solą dla użytkownika pokonującą tablice przewalczonych. Napad, który wyjawia hasła w postaci plaintext: natychmiastowe całkowite ujawnienie.
Silne Szyfrowanie Nie Jest Wystarczające
Przegląd bezpieczeństwa wykrywa system przechowywania danych uwierzytelniających. Hasła są przechowywane za pomocą szyfrowania AES-256-CBC z kluczem na serwerze. Raport audytu oznacza to jako wadę Glass Safe.
Zespół ds. programowania odpowiada: 'AES-256 to najsilniejszy szyfr symetryczny dostępny. Klucz znajduje się w modułach bezpieczeństwa sprzętowego. Nieprzyjaciel nie może zdekryptować tych hasł.'.