2017-07-21 116 views
6

Chcę przechowywać niektóre dane zaszyfrowane, na przykład takie jak menedżer haseł, w którym hasło główne odblokowuje wszystkie hasła aplikacji/lokacji.Zmienianie hasła głównego używanego do szyfrowania

Rozglądając się znalazłem kilka przykładów takich jak this, ale wydaje się, że używają one hasła jako części szyfrowania, podobnie jak sól w haszowaniu. Oznacza to, że do odszyfrowania potrzebujesz dokładnie tego samego hasła, abyś nigdy nie mógł zmienić hasła. To nie wydaje się wspaniałe z punktu widzenia bezpieczeństwa/użyteczności; jeśli PW zostanie naruszony, musisz przerobić całą bazę danych na inny PW.

W jaki sposób utworzyć system, w którym można zmienić hasło główne? Czy robisz prostą weryfikację logowania, a następnie używasz łańcucha do szyfrowania/odszyfrowywania? Czy statyczna natura i przechowywanie tego ciągu nie byłyby niebezpieczne?

Znam trochę PHP i odrobinę kodu Javascript, więc jeśli masz przykłady w tych językach, które będą miłe, ale bardziej ogólne wyjaśnienie wysokiego poziomu jest również bardzo doceniane.

+1

'Oznacza to, że do odszyfrowania potrzebujesz dokładnie tego samego - - tak, tak, jak inaczej byś odszyfrował, gdyby nie ten sam klucz? Poszukujesz systemu, w którym możesz mieć N kluczy do odszyfrowania tego samego tekstu? Jest to możliwe tylko wtedy, gdy zaszyfrujesz ten sam tekst N razy klawiszem N, więc jeśli jeden klucz zostanie zgubiony, otrzymasz klucze N-1 do odszyfrowania danych. Twierdzę, że to jest naprawdę dobre dla bezpieczeństwa, ponieważ masz mieć tylko jeden klucz w historii. Jeśli zmienisz klucz, po prostu ponownie zaszyfruj wszystko za pomocą tego klucza, gdzie jest problem? Szyfrowanie to zmienna bestia, co dokładnie próbujesz rozwiązać? – Mjh

+0

Intuicja mówi, że możesz użyć hasła głównego do zaszyfrowania rzeczywistego klucza szyfrowania (tak jak chronisz hasła prywatne SSH), ale właściwe szyfrowanie jest naprawdę trudne, a intuicja często staje na przeszkodzie (tutaj bardzo prawdopodobne jest, że klucz szyfrowania przechowywany gdzieś jest złym pomysłem). W każdym razie zgadzam się z Mjh, że możesz edytować pytanie i pewne szczegóły dotyczące tego, dlaczego obawiasz się, że ponowne szyfrowanie wszystkiego nie jest możliwe. Czy mówimy o bardzo dużych danych? Czy martwisz się integralnością danych, jeśli nastąpi ponowne zaszyfrowanie wsadowe? –

Odpowiedz

1

Można użyć kryptografii z kluczem publicznym, używając klucza publicznego do szyfrowania danych i hasła w kluczu prywatnym, które można zmienić.

Jednym rozwiązaniem byłoby: 1) Generowanie RSA kluczy prywatnych i publicznych (na Ubuntu):

openssl genrsa -des3 -out private.key 1024 
openssl rsa -in private.key -pubout > public.key 

2) Za pomocą klucza publicznego do szyfrowania:

$key = file_get_contents('/path/to/public.key'); 
openssl_public_encrypt("password", $encryptedData, $key); 

zaoszczędzić $ encryptedData do twoja baza danych (nie możesz użyć tego ciągu jako hasha hasła do dopasowania do logowania, ponieważ $ encryptedData ma losowe bity dodane przed szyfrowaniem, nadal będziesz musiał użyć funkcji hash dla haseł).

3) Za pomocą klucza prywatnego do odszyfrowania, podając hasło:

$key = openssl_pkey_get_private(file_get_contents('/path/to/private.key'), $password); 

if($key === false) { 
    // false password 
    die; 
} 
openssl_private_decrypt($encryptedData, $decryptedData, $key); 

4) Zmień hasło:

openssl rsa -des3 -in private.key -out private.key 

To daje 2 zalety:

  • Oddzielna szyfrowanie & aplikacji odszyfrowywania, szyfrowanie nie wymaga klucza prywatnego ani hasła.
  • Hasło nie musi być zapisane w aplikacji.

Spowoduje to spełnienie podstawowego wymogu dotyczącego możliwości zmiany hasła, a nie ponownego szyfrowania danych.

Jeśli chcesz dodatkowo zabezpieczyć swój klucz prywatny (aby uniemożliwić php bezpośredni dostęp do Twojego klucza prywatnego, co jest przydatne w przypadku włamania do Twojej aplikacji), możesz utworzyć w swoim systemie usługę odszyfrowywania, której możesz użyć wysłać zaszyfrowane dane za pomocą hasła i uzyskać odszyfrowane dane.

+0

Tak, jak wiesz, twój protokół tutaj jest podatny na atak wyroczni, ponieważ 'openssl_private_decrypt()' domyślnie dopełnia PKCS1v1.5. –

4

Istnieje kilka podejść, które działają. Jannes's answer odnosi się do praktycznego rozwiązania (chociaż uwaga na vulnerabilities in openssl_private_decrypt()).

Jeśli używasz Defuse Security's PHP encryption library, klucze chronione hasłem są usuwane.(Jest obecnie jednym open pull request do rozwiązania dokonywania operacji „Zmiana hasła” bez szwu i łatwy w obsłudze.)

Zobacz także: https://github.com/defuse/php-encryption/blob/master/docs/classes/KeyProtectedByPassword.md

Jak zrobić system, w którym można zmienić hasło główne?

coś takiego:

  1. wygenerować silny losowy klucz. Nazwiemy to secret.
  2. Wyodrębnij oddzielny klucz z głównego hasła użytkownika i statycznej soli (wygenerowanej jednorazowo z bezpiecznego kryptograficznie generatora liczb losowych). Nazwiemy to passwordKey.
    • Argon2id(password, salt) =>passwordKey
  3. Szyfrowanie secret z passwordKey, używając trybu bezpiecznego AEAD o losowej nonce i zapisać wynik obok soli.
    • $saved = $salt . $nonce . sodium_crypto_secretbox($secret, $nonce, $passwordKey);
  4. Same dane rzeczywiste będą szyfrowane z secret, nie passwordKey.

Jeśli chcesz zmienić hasło, po prostu powtórz kroki 2 i 3 z nowym hasłem (i inną solą).

Dla Argon2id można używać sodium_crypto_pwhash() na PHP 7.2 i nowszych.