Jedną rzeczą, o której tutaj nie wspomniałem, chociaż jest to rozszerzenie odpowiedzi Marcusa Adamsa, jest to, że nie powinieneś używać jednej informacji do identyfikacji i uwierzytelniania użytkownika, jeśli istnieje możliwość ataków czasowych , co może użyj różnic w czasach odpowiedzi, aby zgadnąć, jak daleko zaszło porównanie ciągów.
Jeśli używasz systemu, który używa „klucza” do wyszukania użytkownika lub danych uwierzytelniających, ta informacja może być odgadywana stopniowo w czasie, wysyłając tysiące żądań i badając czas potrzebny do znalezienia (lub nie) bazy danych znajdź) rekord. Jest to szczególnie ważne, jeśli „klucz” jest przechowywany w postaci zwykłego tekstu zamiast jednokierunkowego skrótu klucza. Chcesz przechowywać klucze użytkowników w postaci zwykłego tekstu lub zaszyfrowanych symetrycznie, jeśli chcesz ponownie wyświetlić klucz użytkownikowi.
Mając drugą informację, „tajną”, możesz najpierw wyszukać użytkownika lub poświadczenie za pomocą „klucza”, który może być podatny na atak czasowy, a następnie użyć funkcji porównywania z bezpiecznym czasem, aby sprawdzić wartość tajemnica".
Oto implementacja tej funkcji w Pythonie:
https://github.com/python/cpython/blob/cd8295ff758891f21084a6a5ad3403d35dda38f7/Modules/_operator.c#L727
I jest ujawniony w hmac
bibliotece (i prawdopodobnie innych):
https://docs.python.org/3/library/hmac.html#hmac.compare_digest
Należy tu zauważyć, że nie sądzę, aby ten rodzaj ataku zadziałał na wartościach, które są zaszyfrowane lub zaszyfrowane przed wyszukiwaniem, ponieważ porównywane wartości zmieniają się losowo za każdym razem, gdy zmienia się znak w ciągu wejściowym. Znalazłem dobre wytłumaczenie tego tutaj .
Rozwiązania do przechowywania kluczy API to:
- Użyj oddzielnego klucza i hasła, użyj klucza do wyszukania rekordu i użyj bezpiecznego porównania, aby sprawdzić sekret. Pozwala to ponownie pokazać użytkownikowi klucz i sekret.
- Użyj oddzielnego klucza i sekretu, użyj symetrycznego, deterministycznego szyfrowania sekretu i wykonaj normalne porównanie zaszyfrowanych sekretów. Pozwala to na ponowne pokazanie użytkownikowi klucza i tajnego klucza i może uchronić Cię przed koniecznością wdrażania bezpiecznego porównania czasowego.
- Użyj oddzielnego klucza i sekretu, wyświetl sekret, zhaszuj i zapisz go, a następnie wykonaj normalne porównanie zaszyfrowanego sekretu. Eliminuje to konieczność korzystania z szyfrowania dwukierunkowego i ma dodatkową zaletę polegającą na zachowaniu tajemnicy w przypadku naruszenia bezpieczeństwa systemu. Ma tę wadę, że nie można ponownie pokazać tajemnicy użytkownikowi.
- Użyj jednego klucza , pokaż go raz użytkownikowi, zhaszuj, a następnie przeprowadź normalne wyszukiwanie klucza zaszyfrowanego lub zaszyfrowanego. Używa jednego klucza, ale nie można go ponownie pokazać użytkownikowi. Ma tę zaletę, że zapewnia bezpieczeństwo kluczy w przypadku naruszenia bezpieczeństwa systemu.
- Użyj jednego klucza , pokaż go użytkownikowi, zaszyfruj i przeprowadź normalne wyszukiwanie zaszyfrowanego klucza . Może być ponownie pokazany użytkownikowi, ale kosztem narażenia kluczy na włamanie do systemu.
Spośród nich myślę, że 3 to najlepsza równowaga między bezpieczeństwem a wygodą. Widziałem to zaimplementowane na wielu stronach internetowych podczas uzyskiwania wydanych kluczy.
Zapraszam również wszystkich ekspertów ds. Bezpieczeństwa do krytyki tej odpowiedzi. Chciałem tylko, żeby to było kolejnym punktem dyskusji.