Szyfrowanie dwukierunkowe: muszę przechowywać hasła, które można odzyskać

174

Tworzę aplikację, która będzie przechowywać hasła, które użytkownik może odzyskać i zobaczyć. Hasła dotyczą urządzenia sprzętowego, więc nie ma mowy o sprawdzaniu ich pod kątem skrótów.

Muszę wiedzieć:

  1. Jak zaszyfrować i odszyfrować hasło w PHP?

  2. Jaki jest najbezpieczniejszy algorytm szyfrowania haseł?

  3. Gdzie mogę przechowywać klucz prywatny?

  4. Czy zamiast przechowywać klucz prywatny, warto wymagać od użytkowników wprowadzenia klucza prywatnego za każdym razem, gdy potrzebują odszyfrowania hasła? (Można zaufać użytkownikom tej aplikacji)

  5. W jaki sposób można ukraść i odszyfrować hasło? Czego muszę być świadomy?

HajdarA
źródło
1
Uwaga: Libsodium jest teraz wkompilowany do rdzenia PHP dla> = 7.2. Byłoby to teraz rozwiązanie typu „przejdź do”, ponieważ jest pełne nowoczesnych metod w przeciwieństwie do mcrypt, który jest uważany za przestarzały i został usunięty.
Exhibitioner

Odpowiedzi:

212

Osobiście użyłbym tak, mcryptjak inni opublikowali. Ale jest o wiele więcej wartych uwagi ...

  1. Jak zaszyfrować i odszyfrować hasło w PHP?

    Poniżej znajdziesz silną klasę, która zajmie się wszystkim za Ciebie:

  2. Jaki jest najbezpieczniejszy algorytm szyfrowania haseł?

    najbezpieczniejszy ? ktokolwiek z nich. Najbezpieczniejszą metodą, jeśli zamierzasz szyfrować, jest ochrona przed lukami w ujawnianiu informacji (XSS, zdalne włączanie itp.). Jeśli się wydostanie, atakujący może w końcu złamać szyfrowanie (żadne szyfrowanie nie jest w 100% nieodwracalne bez klucza - jak zauważa @NullUserException, nie jest to do końca prawdą. Istnieją pewne schematy szyfrowania, których nie można złamać, takie jak OneTimePad ) .

  3. Gdzie mogę przechowywać klucz prywatny?

    Chciałbym użyć 3 kluczy. Jeden jest dostarczany przez użytkownika, jeden jest specyficzny dla aplikacji, a drugi dla użytkownika (jak sól). Klucz aplikacji może być przechowywany w dowolnym miejscu (w pliku konfiguracyjnym poza katalogiem głównym, w zmiennej środowiskowej itp.). Specyficzne dla użytkownika będzie przechowywane w kolumnie w bazie danych obok zaszyfrowanego hasła. Podany przez użytkownika nie byłby przechowywany. Następnie zrobiłbyś coś takiego:

    $key = $userKey . $serverKey . $userSuppliedKey;

    Zaletą jest to, że dowolne 2 klucze mogą zostać naruszone bez narażania danych. W przypadku ataku typu SQL Injection mogą zdobyć $userKeydrugie 2. Jeśli istnieje exploit na serwerze lokalnym, mogą zdobyć $userKeyi $serverKey, ale nie trzeci $userSuppliedKey. Jeśli pobiją użytkownika kluczem, mogą dostać $userSuppliedKey, ale pozostałe 2 nie (ale z drugiej strony, jeśli użytkownik zostanie pobity kluczem, i tak spóźnisz się).

  4. Czy zamiast przechowywać klucz prywatny, warto wymagać od użytkowników wprowadzenia klucza prywatnego za każdym razem, gdy potrzebują odszyfrowania hasła? (Można zaufać użytkownikom tej aplikacji)

    Absolutnie. Właściwie to jedyny sposób, w jaki bym to zrobił. W przeciwnym razie musisz przechowywać niezaszyfrowaną wersję w trwałym formacie pamięci (pamięć współdzielona, ​​taka jak APC lub memcached, lub w pliku sesji). To narażanie się na dodatkowe kompromisy. Nigdy nie przechowuj niezaszyfrowanej wersji hasła w niczym z wyjątkiem zmiennej lokalnej.

  5. W jaki sposób można ukraść i odszyfrować hasło? Czego muszę być świadomy?

    Każda forma naruszenia bezpieczeństwa Twoich systemów umożliwi im przeglądanie zaszyfrowanych danych. Jeśli mogą wstrzyknąć kod lub dostać się do systemu plików, mogą przeglądać odszyfrowane dane (ponieważ mogą edytować pliki, które odszyfrowują dane). Każda forma ataku typu Replay lub MITM zapewni im również pełny dostęp do odpowiednich kluczy. Sniffowanie nieprzetworzonego ruchu HTTP również da im klucze.

    Używaj SSL dla całego ruchu. I upewnij się, że nic na serwerze nie ma jakichkolwiek luk w zabezpieczeniach (CSRF, XSS, SQL Injection, Eskalacja uprawnień, zdalne wykonanie kodu itp.).

Edycja: Oto implementacja klasy PHP silnej metody szyfrowania:

/**
 * A class to handle secure encryption and decryption of arbitrary data
 *
 * Note that this is not just straight encryption.  It also has a few other
 *  features in it to make the encrypted data far more secure.  Note that any
 *  other implementations used to decrypt data will have to do the same exact
 *  operations.  
 *
 * Security Benefits:
 *
 * - Uses Key stretching
 * - Hides the Initialization Vector
 * - Does HMAC verification of source data
 *
 */
class Encryption {

    /**
     * @var string $cipher The mcrypt cipher to use for this instance
     */
    protected $cipher = '';

    /**
     * @var int $mode The mcrypt cipher mode to use
     */
    protected $mode = '';

    /**
     * @var int $rounds The number of rounds to feed into PBKDF2 for key generation
     */
    protected $rounds = 100;

    /**
     * Constructor!
     *
     * @param string $cipher The MCRYPT_* cypher to use for this instance
     * @param int    $mode   The MCRYPT_MODE_* mode to use for this instance
     * @param int    $rounds The number of PBKDF2 rounds to do on the key
     */
    public function __construct($cipher, $mode, $rounds = 100) {
        $this->cipher = $cipher;
        $this->mode = $mode;
        $this->rounds = (int) $rounds;
    }

    /**
     * Decrypt the data with the provided key
     *
     * @param string $data The encrypted datat to decrypt
     * @param string $key  The key to use for decryption
     * 
     * @returns string|false The returned string if decryption is successful
     *                           false if it is not
     */
    public function decrypt($data, $key) {
        $salt = substr($data, 0, 128);
        $enc = substr($data, 128, -64);
        $mac = substr($data, -64);

        list ($cipherKey, $macKey, $iv) = $this->getKeys($salt, $key);

        if (!hash_equals(hash_hmac('sha512', $enc, $macKey, true), $mac)) {
             return false;
        }

        $dec = mcrypt_decrypt($this->cipher, $cipherKey, $enc, $this->mode, $iv);

        $data = $this->unpad($dec);

        return $data;
    }

    /**
     * Encrypt the supplied data using the supplied key
     * 
     * @param string $data The data to encrypt
     * @param string $key  The key to encrypt with
     *
     * @returns string The encrypted data
     */
    public function encrypt($data, $key) {
        $salt = mcrypt_create_iv(128, MCRYPT_DEV_URANDOM);
        list ($cipherKey, $macKey, $iv) = $this->getKeys($salt, $key);

        $data = $this->pad($data);

        $enc = mcrypt_encrypt($this->cipher, $cipherKey, $data, $this->mode, $iv);

        $mac = hash_hmac('sha512', $enc, $macKey, true);
        return $salt . $enc . $mac;
    }

    /**
     * Generates a set of keys given a random salt and a master key
     *
     * @param string $salt A random string to change the keys each encryption
     * @param string $key  The supplied key to encrypt with
     *
     * @returns array An array of keys (a cipher key, a mac key, and a IV)
     */
    protected function getKeys($salt, $key) {
        $ivSize = mcrypt_get_iv_size($this->cipher, $this->mode);
        $keySize = mcrypt_get_key_size($this->cipher, $this->mode);
        $length = 2 * $keySize + $ivSize;

        $key = $this->pbkdf2('sha512', $key, $salt, $this->rounds, $length);

        $cipherKey = substr($key, 0, $keySize);
        $macKey = substr($key, $keySize, $keySize);
        $iv = substr($key, 2 * $keySize);
        return array($cipherKey, $macKey, $iv);
    }

    /**
     * Stretch the key using the PBKDF2 algorithm
     *
     * @see http://en.wikipedia.org/wiki/PBKDF2
     *
     * @param string $algo   The algorithm to use
     * @param string $key    The key to stretch
     * @param string $salt   A random salt
     * @param int    $rounds The number of rounds to derive
     * @param int    $length The length of the output key
     *
     * @returns string The derived key.
     */
    protected function pbkdf2($algo, $key, $salt, $rounds, $length) {
        $size   = strlen(hash($algo, '', true));
        $len    = ceil($length / $size);
        $result = '';
        for ($i = 1; $i <= $len; $i++) {
            $tmp = hash_hmac($algo, $salt . pack('N', $i), $key, true);
            $res = $tmp;
            for ($j = 1; $j < $rounds; $j++) {
                 $tmp  = hash_hmac($algo, $tmp, $key, true);
                 $res ^= $tmp;
            }
            $result .= $res;
        }
        return substr($result, 0, $length);
    }

    protected function pad($data) {
        $length = mcrypt_get_block_size($this->cipher, $this->mode);
        $padAmount = $length - strlen($data) % $length;
        if ($padAmount == 0) {
            $padAmount = $length;
        }
        return $data . str_repeat(chr($padAmount), $padAmount);
    }

    protected function unpad($data) {
        $length = mcrypt_get_block_size($this->cipher, $this->mode);
        $last = ord($data[strlen($data) - 1]);
        if ($last > $length) return false;
        if (substr($data, -1 * $last) !== str_repeat(chr($last), $last)) {
            return false;
        }
        return substr($data, 0, -1 * $last);
    }
}

Należy pamiętać, że używam funkcji dodana w PHP 5.6: hash_equals. Jeśli masz mniej niż 5,6, możesz użyć tej zastępczej funkcji, która implementuje funkcję porównywania z bezpiecznym czasem, używając podwójnej weryfikacji HMAC :

function hash_equals($a, $b) {
    $key = mcrypt_create_iv(128, MCRYPT_DEV_URANDOM);
    return hash_hmac('sha512', $a, $key) === hash_hmac('sha512', $b, $key);
}

Stosowanie:

$e = new Encryption(MCRYPT_BLOWFISH, MCRYPT_MODE_CBC);
$encryptedData = $e->encrypt($data, $key);

Następnie, aby odszyfrować:

$e2 = new Encryption(MCRYPT_BLOWFISH, MCRYPT_MODE_CBC);
$data = $e2->decrypt($encryptedData, $key);

Zwróć uwagę, że użyłem $e2drugiego razu, aby pokazać, że różne instancje nadal będą poprawnie odszyfrowywać dane.

Teraz, jak to działa / dlaczego używać go zamiast innego rozwiązania:

  1. Klucze

    • Klucze nie są używane bezpośrednio. Zamiast tego klucz jest rozciągany przez standardowe wyprowadzenie PBKDF2.

    • Klucz używany do szyfrowania jest unikalny dla każdego zaszyfrowanego bloku tekstu. Dlatego dostarczony klucz staje się „kluczem głównym”. Dlatego ta klasa zapewnia rotację kluczy dla kluczy szyfrujących i uwierzytelniających.

    • WAŻNA UWAGA , $roundsparametr jest skonfigurowany dla prawdziwych losowych kluczy o wystarczającej sile (co najmniej 128 bitów losowych kluczy Cryptographically Secure). Jeśli zamierzasz używać hasła lub nielosowego klucza (lub mniej losowego niż 128 bitów CS losowo), musisz zwiększyć ten parametr. Sugerowałbym minimum 10000 haseł (im więcej cię stać, tym lepiej, ale doda to do środowiska uruchomieniowego) ...

  2. Integralność danych

    • Zaktualizowana wersja używa ENCRYPT-THEN-MAC, co jest znacznie lepszą metodą zapewnienia autentyczności zaszyfrowanych danych.
  3. Szyfrowanie:

    • Używa mcrypt, aby faktycznie wykonać szyfrowanie. Sugerowałbym użycie albo MCRYPT_BLOWFISHlub MCRYPT_RIJNDAEL_128szyfrów i MCRYPT_MODE_CBCdla trybu. Jest wystarczająco silny i nadal dość szybki (cykl szyfrowania i deszyfrowania zajmuje około 1/2 sekundy na moim komputerze).

Teraz, jeśli chodzi o punkt 3 z pierwszej listy, to dałoby ci taką funkcję:

function makeKey($userKey, $serverKey, $userSuppliedKey) {
    $key = hash_hmac('sha512', $userKey, $serverKey);
    $key = hash_hmac('sha512', $key, $userSuppliedKey);
    return $key;
}

Możesz go rozciągnąć w makeKey() funkcji, ale ponieważ zostanie rozciągnięty później, nie ma to większego sensu.

Jeśli chodzi o wielkość magazynu, zależy to od zwykłego tekstu. Blowfish używa 8-bajtowego rozmiaru bloku, więc będziesz mieć:

  • 16 bajtów na sól
  • 64 bajty dla pliku hmac
  • długość danych
  • Wypełnienie tak, aby długość danych% 8 == 0

W przypadku 16-znakowego źródła danych do zaszyfrowania będzie 16 znaków. Oznacza to, że rzeczywisty rozmiar zaszyfrowanych danych wynosi 16 bajtów ze względu na wypełnienie. Następnie dodaj 16 bajtów na sól i 64 bajty na hmac, a całkowity przechowywany rozmiar wynosi 96 bajtów. Więc co najwyżej jest 80 znaków, aw najgorszym 87 znaków ...

Mam nadzieję że to pomogło...

Uwaga: 12/11/12: Właśnie zaktualizowałem tę klasę o DUŻO lepszą metodę szyfrowania, używając lepiej wyprowadzonych kluczy i naprawiając generowanie MAC ...

ircmaxell
źródło
3
Ktoś nie rozumie, co to znaczy „przerwa”. @IRC niezła robota na zajęciach, to cholernie fajny kod.
jcolebrand
1
Poniższe zwraca wartość false. Każdy pomysł, dlaczego? $ x = nowe szyfrowanie (MCRYPT_BlOWFISH, MCRYPT_MODE_CBC); $ test = $ x-> zaszyfruj ("test", "a"); echo var_dump ($ x-> deszyfruj ($ test, "a"));
Długość fali
2
Aha i znowu w funkcji deszyfrującej zmieniając dwa -64s na -128pomogły (więc dostajesz $enc = substr($data, 128, -128)i$mac = substr($data, -128);
cosmorogers
4
@ircmaxell Minęło sporo czasu od ostatniej aktualizacji kodu, więc zastanawiam się, czy jest aktualny. Potrzebuję czegoś podobnego do aplikacji finansowej i byłoby miło, gdybyś
zgodził się
2
Ostrzeżenie! Rozszerzenie mcrypt było porzucone przez prawie dekadę i było dość skomplikowane w użyciu. Dlatego został uznany za przestarzały na korzyść OpenSSL, gdzie zostanie usunięty z rdzenia i do PECL w PHP 7.2. th1.php.net/manual/en/migration71.deprecated.php
vee
15

Jak zaszyfrować i odszyfrować hasło w PHP? Wdrażając jeden z wielu algorytmów szyfrowania. (lub używając jednej z wielu bibliotek)

Jaki jest najbezpieczniejszy algorytm szyfrowania haseł? Istnieje mnóstwo różnych algorytmów, z których żaden nie jest w 100% bezpieczny. Ale wiele z nich jest wystarczająco bezpiecznych dla celów handlowych, a nawet wojskowych

Gdzie mogę przechowywać klucz prywatny? Jeśli zdecydowałeś się zaimplementować klucz publiczny - algorytm kryptograficzny (np. RSA), nie przechowujesz klucza prywatnego. użytkownik ma klucz prywatny. Twój system ma klucz publiczny, który można przechowywać w dowolnym miejscu.

Czy zamiast przechowywać klucz prywatny, warto wymagać od użytkowników wprowadzania klucza prywatnego za każdym razem, gdy potrzebują odszyfrowania hasła? (Użytkownicy tej aplikacji mogą być zaufani) Cóż, jeśli twój użytkownik pamięta absurdalnie długie liczby pierwsze - tak, czemu nie. Ale generalnie musisz wymyślić system, który pozwoli użytkownikowi gdzieś przechowywać klucz.

W jaki sposób można ukraść i odszyfrować hasło? Czego muszę być świadomy? Zależy to od zastosowanego algorytmu. Jednak zawsze upewnij się, że nie wysyłasz niezaszyfrowanego hasła do lub od użytkownika. Zaszyfruj / odszyfruj go po stronie klienta lub użyj protokołu https (lub użyj innych środków kryptograficznych, aby zabezpieczyć połączenie między serwerem a klientem).

Jeśli jednak wszystko, czego potrzebujesz, to przechowywanie haseł w sposób zaszyfrowany, sugerowałbym użycie prostego szyfru XOR. Główny problem z tym algorytmem polega na tym, że można go łatwo złamać za pomocą analizy częstotliwości. Jednak ponieważ generalnie hasła nie są tworzone z długich akapitów tekstu w języku angielskim, nie sądzę, abyś się tym przejmował. Drugi problem z XOR Cipher polega na tym, że jeśli masz wiadomość zarówno w postaci zaszyfrowanej, jak i odszyfrowanej, możesz łatwo znaleźć hasło, za pomocą którego została zaszyfrowana. Ponownie, nie jest to duży problem w twoim przypadku, ponieważ dotyczy tylko użytkownika, który został już naruszony w inny sposób.

Ivan
źródło
W odpowiedzi 3, kiedy mówisz, że użytkownicy mają klucz prywatny, nie rozumiem, co to oznacza. Nie zalecamy ręcznego przekazywania kluczy prywatnych do aplikacji przez użytkownika, więc w jaki inny sposób klucze prywatne są przekazywane do aplikacji?
HyderA
To trochę problem. Klucz prywatny można zapisać w pliku tekstowym, a następnie skopiować wklejony do aplikacji. Klucz może być również przechowywany na serwerze, ale w tym przypadku nadal powinien być zaszyfrowany innym algorytmem szyfrowania, takim jak XOR. Użycie XOR w tym przypadku jest wystarczająco bezpieczne, ponieważ jest tylko jedna para hasło-wiadomość, a wiadomość jest dość losowa, więc analiza częstotliwości nie może być używana.
Ivan
4
Z pewnością nie polecałbym samodzielnego wdrażania algorytmu szyfrowania, istnieje zbyt wiele potencjalnych pułapek, a istniejące biblioteki zostały przetestowane i przeanalizowane przez wiele osób.
Długie uszy
Główny problem z XOR polega na tym, że jeśli ktoś ukradnie dane aplikacji i zna tylko jedno z haseł użytkownika, może odszyfrować wszystkie inne hasła tego użytkownika.
Długie uszy
1
@Ivan: tak, ale to jeden z przypadków, w których uważam, że majsterkowanie jest naprawdę złe, chyba że NAPRAWDĘ rozumiesz kryptografię. Istnieją silne szyfry, które istnieją, dlaczego ich nie użyć?
ircmaxell
13
  1. Funkcja PHP, której szukasz, to Mcrypt ( http://www.php.net/manual/en/intro.mcrypt.php ).

Przykład z instrukcji jest nieznacznie zredagowany na potrzeby tego przykładu):

<?php
$iv_size = mcrypt_get_iv_size(MCRYPT_BLOWFISH, MCRYPT_MODE_ECB);
$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
$key = "This is a very secret key";
$pass = "PasswordHere";
echo strlen($pass) . "\n";

$crypttext = mcrypt_encrypt(MCRYPT_BLOWFISH, $key, $pass, MCRYPT_MODE_ECB, $iv);
echo strlen($crypttext) . "\n";
?>

Do odszyfrowania hasła użyłbyś mcrypt_decrypt .

  1. Najlepszy algorytm jest raczej subiektywny - zapytaj 5 osób, uzyskaj 5 odpowiedzi. Osobiście, jeśli domyślny (Blowfish) nie jest dla Ciebie wystarczająco dobry, prawdopodobnie masz większe problemy!

  2. Biorąc pod uwagę, że PHP potrzebuje go do szyfrowania - nie jestem pewien, czy możesz go gdziekolwiek ukryć - mile widziane komentarze na ten temat. Oczywiście obowiązują standardowe najlepsze praktyki kodowania PHP!

  3. Biorąc pod uwagę, że klucz szyfrowania i tak będzie w Twoim kodzie, nie jesteś pewien, co zyskasz, pod warunkiem, że reszta aplikacji będzie bezpieczna.

  4. Oczywiście, jeśli zaszyfrowane hasło i klucz szyfrowania zostaną skradzione, gra się kończy.

Postawiłbym jeźdźca na mojej odpowiedzi - nie jestem ekspertem od kryptografii PHP, ale myślę, że to, na co odpowiedziałem, jest standardową praktyką - mile widziane są komentarze innych.

Jon Rhoades
źródło
$pass = $text. Myślę, że zmienił to, aby odpowiedzieć na pytanie, i nie zauważył drugiego wystąpienia.
HyderA
3
Dwie rzeczy do zapamiętania. Po pierwsze, MCRYPT_MODE_ECBnie używa IV. Po drugie, gdyby tak było, musiałbyś przechowywać IV, ponieważ bez niego nie można odszyfrować danych ...
ircmaxell
„Najlepszy algorytm jest raczej subiektywny - zapytaj 5 osób, uzyskaj 5 odpowiedzi. Osobiście, jeśli domyślny (Blowfish) nie jest dla Ciebie wystarczająco dobry, prawdopodobnie masz większe problemy!” To jest całkowicie błędne. Każdy ekspert od kryptowalut mniej więcej zgodzi się z gist.github.com/tqbf/be58d2d39690c3b366ad, który wyraźnie wyklucza rozdymkę
Scott Arciszewski
6

Wielu użytkowników sugerowało używanie mcrypt ... co jest poprawne, ale lubię pójść o krok dalej, aby ułatwić jego przechowywanie i przesyłanie (ponieważ czasami zaszyfrowane wartości mogą utrudniać ich wysyłanie przy użyciu innych technologii, takich jak curl lub json) .

Po pomyślnym zaszyfrowaniu przy użyciu mcrypt, uruchom go przez base64_encode, a następnie przekonwertuj na kod szesnastkowy. Raz w kodzie szesnastkowym można łatwo przenieść na różne sposoby.

$td = mcrypt_module_open('tripledes', '', 'ecb', '');
$iv = mcrypt_create_iv (mcrypt_enc_get_iv_size($td), MCRYPT_RAND);
$key = substr("SUPERSECRETKEY",0,mcrypt_enc_get_key_size($td));
mcrypt_generic_init($td, $key, $iv);
$encrypted = mcrypt_generic($td, $unencrypted);
$encrypted = $ua."||||".$iv;
mcrypt_generic_deinit($td);
mcrypt_module_close($td);
$encrypted = base64_encode($encrypted);
$encrypted = array_shift(unpack('H*', $encrypted));

A po drugiej stronie:

$encrypted = pack('H*', $encrypted);
$encrypted = base64_decode($encrypted);
list($encrypted,$iv) = explode("||||",$encrypted,2);
$td = mcrypt_module_open('tripledes', '', 'ecb', '');
$key = substr("SUPERSECRETKEY",0,mcrypt_enc_get_key_size($td));
mcrypt_generic_init($td, $key, $iv);
$unencrypted = mdecrypt_generic($td, $encrypted);
mcrypt_generic_deinit($td);
mcrypt_module_close($td);
Bradley
źródło
2
Cóż - to było w 2011 roku: P
Bradley
5

Zasugerowałbym szyfrowanie za pomocą klucza publicznego tylko wtedy, gdy chcesz mieć możliwość ustawienia hasła użytkownika bez jego interakcji (może to być przydatne w przypadku resetowania i udostępniania haseł).

Klucz publiczny

  1. W szczególności rozszerzenie OpenSSLopenssl_public_encrypt iopenssl_private_decrypt
  2. Byłoby to proste RSA zakładając, że Twoje hasła będą pasować do rozmiaru klucza - dopełnienie, w przeciwnym razie potrzebujesz warstwy symetrycznej
  3. Przechowuj oba klucze dla każdego użytkownika. Hasło klucza prywatnego to hasło aplikacji

Symetryczny

  1. Mcrypt rozszerzenie
  2. AES-256 to prawdopodobnie bezpieczny zakład, ale może to być samo w sobie pytanie SO
  3. Nie - to byłoby ich hasło do aplikacji

Obie

4. Tak - użytkownicy musieliby za każdym razem wprowadzać hasło aplikacji, ale przechowywanie go w sesji spowodowałoby inne problemy

5.

  • Jeśli ktoś ukradnie dane aplikacji, jest to tak samo bezpieczne, jak szyfr symetryczny (w schemacie klucza publicznego służy do ochrony klucza prywatnego za pomocą hasła).
  • Twoja aplikacja powinna być zdecydowanie dostępna tylko przez SSL, najlepiej przy użyciu certyfikatów klienta.
  • Rozważ dodanie drugiego czynnika uwierzytelniającego, który będzie używany tylko raz na sesję, np. Token wysłany SMS-em.
Długie uszy
źródło
Unikaj mcrypt, bądź ostrożny z openssl_private_decrypt().
Scott Arciszewski,
2

Próbowałem czegoś takiego, ale pamiętaj, że nie jestem kryptografem ani nie posiadam dogłębnej wiedzy na temat phpżadnego języka programowania. To tylko pomysł. Mój pomysł polega na zapisaniu keyw jakimś pliku lub database(lub wpisaniu ręcznie), którego (lokalizacji) nie da się łatwo przewidzieć (i oczywiście wszystko zostanie kiedyś odszyfrowane, koncepcja polega na wydłużeniu czasu deszyfrowania) i zaszyfrowanie poufnych informacji.

$iv_size = mcrypt_get_iv_size(MCRYPT_BLOWFISH , MCRYPT_MODE_ECB);
$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
$key = "evenifyouaccessmydatabaseyouwillneverfindmyemail";
$text = "[email protected]";
echo "Key : ".$key."<br/>";
echo "Text : ".$text . "<br/>";
echo "Md5 : ".md5($text). "<br/>";
echo "Sha1 : ".sha1($text). "<br/>";



$crypttext = mcrypt_encrypt(MCRYPT_BLOWFISH , $key, $text, MCRYPT_MODE_ECB, $iv);
echo "Crypted Data : ".$crypttext."<br>";

$base64 = base64_encode($crypttext);
echo "Encoded Data : ".$base64."<br/>";
$decode =  base64_decode($base64);


$decryptdata = mcrypt_decrypt(MCRYPT_BLOWFISH , $key, $crypttext, MCRYPT_MODE_ECB, $iv);

echo "Decoded Data : ".ereg_replace("?", null ,  $decryptdata); 
//event if i add '?' to the sting to the text it works, I don't know why.

Należy pamiętać, że to tylko koncepcja. Wszelkie ulepszenia tego kodu byłyby bardzo odczuwalne.

Santosh Linkha
źródło
2

Hasła dotyczą urządzenia sprzętowego, więc nie ma mowy o sprawdzaniu ich pod kątem skrótów

Ech? Nie rozumiem. Czy masz na myśli tylko to, że hasło musi być możliwe do odzyskania?

Jak powiedzieli inni, rozszerzenie mcrypt zapewnia dostęp do wielu funkcji kryptograficznych - jednak zachęcasz użytkowników do umieszczenia wszystkich swoich jajek w jednym koszyku - takim, który będzie potencjalnie celem dla atakujących - i jeśli nawet nie wiesz jak zacząć rozwiązywać problem, to wyrządzasz użytkownikom krzywdę. Nie jesteś w stanie zrozumieć, jak chronić dane.

Większość luk w zabezpieczeniach powstaje nie dlatego, że bazowy algorytm jest wadliwy lub niezabezpieczony, ale z powodu problemów ze sposobem wykorzystania algorytmu w kodzie aplikacji.

To powiedziawszy, można zbudować w miarę bezpieczny system.

Szyfrowanie asymetryczne należy rozważać tylko wtedy, gdy wymaga się, aby użytkownik utworzył bezpieczną wiadomość, którą może odczytać inny (określony) użytkownik. Powodem jest to, że jest kosztowny obliczeniowo. Jeśli chcesz tylko zapewnić repozytorium, w którym użytkownicy będą mogli wprowadzać i pobierać własne dane, wystarczające jest szyfrowanie symetryczne.

Jeśli jednak przechowujesz klucz do odszyfrowania wiadomości w tym samym miejscu, w którym znajduje się zaszyfrowana wiadomość (lub gdzie jest przechowywana zaszyfrowana wiadomość), system nie jest bezpieczny. Użyj tego samego tokena do uwierzytelnienia użytkownika, co w przypadku klucza deszyfrującego (lub w przypadku szyfrowania asymetrycznego użyj tokena jako frazy hasła klucza prywatnego). Ponieważ będziesz musiał przechowywać token na serwerze, na którym odbywa się deszyfrowanie, przynajmniej tymczasowo, możesz rozważyć użycie niemożliwego do przeszukiwania substratu do przechowywania sesji lub przekazanie tokena bezpośrednio do demona powiązanego z sesją, który będzie przechowywał token w pamięci i deszyfrowanie wiadomości na żądanie.

symcbean
źródło
1

Użyj password_hash i password_verify

<?php
/**
 * In this case, we want to increase the default cost for BCRYPT to 12.
 * Note that we also switched to BCRYPT, which will always be 60 characters.
 */
$options = [
    'cost' => 12,
];
echo password_hash("rasmuslerdorf", PASSWORD_BCRYPT, $options)."\n";
?>

I odszyfrować:

<?php
// See the password_hash() example to see where this came from.
$hash = '$2y$07$BCryptRequires22Chrcte/VlQH0piJtjXl.0t1XkA8pw9dMXTpOq';

if (password_verify('rasmuslerdorf', $hash)) {
    echo 'Password is valid!';
} else {
    echo 'Invalid password.';
}
?>
jvitoroc
źródło