Двустороннее шифрование: мне нужно хранить пароли, которые можно получить

174

Я создаю приложение, которое будет хранить пароли, которые пользователь может получить и увидеть. Пароли предназначены для аппаратного устройства, поэтому о проверке хэшей не может быть и речи.

Что мне нужно знать, это:

  1. Как зашифровать и расшифровать пароль в PHP?

  2. Какой алгоритм шифрования паролей является самым безопасным?

  3. Где я могу хранить закрытый ключ?

  4. Вместо того, чтобы хранить закрытый ключ, стоит ли требовать, чтобы пользователи вводили закрытый ключ каждый раз, когда им нужен расшифрованный пароль? (Пользователям этого приложения можно доверять)

  5. Каким образом пароль может быть украден и расшифрован? Что мне нужно знать?

HyderA
источник
1
Примечание: Libsodium теперь скомпилирован в ядро ​​PHP для> = 7.2. Теперь это будет решение «перейти к», так как оно полно современных методов, в отличие от mcrypt, который считается устаревшим и был удален.
выставки

Ответы:

212

Лично я бы использовал mcryptкак другие опубликованные. Но есть еще много чего отметить ...

  1. Как зашифровать и расшифровать пароль в PHP?

    Смотрите ниже сильный класс, который позаботится обо всем для вас:

  2. Какой алгоритм шифрования паролей является самым безопасным?

    самый безопасный ? любой из них. Самый безопасный способ шифрования - это защита от уязвимостей раскрытия информации (XSS, удаленное включение и т. Д.). Если он выходит, злоумышленник может в конечном итоге взломать шифрование (никакое шифрование не является на 100% необратимым без ключа - как указывает @NullUserException, это не совсем верно. Существуют некоторые схемы шифрования, которые невозможно взломать, например OneTimePad ) ,

  3. Где я могу хранить закрытый ключ?

    То, что я хотел бы сделать, это использовать 3 ключа. Один из них предоставляется пользователем, один - для конкретного приложения, а другой - для конкретного пользователя (например, соль). Специфический ключ приложения может храниться где угодно (в файле конфигурации вне корневого веб-узла, в переменной среды и т. Д.). Конкретный пользователь будет храниться в столбце в БД рядом с зашифрованным паролем. Предоставленный пользователем один не будет сохранен. Затем вы бы сделали что-то вроде этого:

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

    Преимущество заключается в том, что любые 2 ключа могут быть скомпрометированы без компрометации данных. Если есть атака SQL Injection, они могут получить $userKey, но не другой 2. Если есть эксплойт локального сервера, они могут получить $userKeyи $serverKey, но не третий $userSuppliedKey. Если они избивают пользователя гаечным ключом, они могут получить $userSuppliedKey, но не два других (но, опять же, если пользователя избивают гаечным ключом, вы все равно опоздаете).

  4. Вместо того, чтобы хранить закрытый ключ, стоит ли требовать, чтобы пользователи вводили закрытый ключ каждый раз, когда им нужен расшифрованный пароль? (Пользователям этого приложения можно доверять)

    Абсолютно. На самом деле, это единственный способ, которым я бы это сделал. В противном случае вам потребуется хранить незашифрованную версию в формате длительного хранения (совместно используемая память, такая как APC или memcached, или в файле сеанса). Это подвергает себя дополнительным компромиссам. Никогда не храните незашифрованную версию пароля ни в чем, кроме локальной переменной.

  5. Каким образом пароль может быть украден и расшифрован? Что мне нужно знать?

    Любая форма компрометации ваших систем позволит им просматривать зашифрованные данные. Если они могут внедрить код или получить доступ к вашей файловой системе, они могут просматривать расшифрованные данные (поскольку они могут редактировать файлы, которые расшифровывают данные). Любая форма Replay или MITM-атаки также даст им полный доступ к задействованным ключам. Обнюхивание необработанного HTTP-трафика также даст им ключи.

    Используйте SSL для всего трафика. И убедитесь, что на сервере нет никаких уязвимостей (CSRF, XSS, SQL-инъекция, повышение привилегий, удаленное выполнение кода и т. Д.).

Изменить: Вот реализация класса PHP метода сильного шифрования класса:

/**
 * 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);
    }
}

Обратите внимание , что я использую функцию добавлена в PHP 5.6: hash_equals. Если у вас уровень ниже 5.6, вы можете использовать эту функцию замещения, которая реализует функцию сравнения, безопасную по времени, с использованием двойной проверки 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);
}

Использование:

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

Затем расшифровать:

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

Обратите внимание, что я использовал $e2второй раз, чтобы показать вам, что разные экземпляры все равно будут правильно расшифровывать данные.

Теперь, как это работает / почему использовать его поверх другого решения:

  1. Ключи

    • Ключи не используются напрямую. Вместо этого ключ растягивается стандартным деривацией PBKDF2.

    • Ключ, используемый для шифрования, уникален для каждого зашифрованного блока текста. Таким образом, предоставленный ключ становится «главным ключом». Поэтому этот класс обеспечивает поворот ключей для ключей шифрования и аутентификации.

    • ВАЖНОЕ ПРИМЕЧАНИЕ : $roundsпараметр настроен для истинных случайных ключей достаточной силы (как минимум 128 битов криптографически защищенных случайных ключей). Если вы собираетесь использовать пароль или неслучайный ключ (или менее случайный, чем 128 бит случайного CS), вы должны увеличить этот параметр. Я бы предложил минимум 10000 для паролей (чем больше вы можете себе позволить, тем лучше, но это увеличит время выполнения) ...

  2. Целостность данных

    • В обновленной версии используется ENCRYPT-THEN-MAC, который является гораздо лучшим методом для обеспечения подлинности зашифрованных данных.
  3. Шифрование:

    • Он использует mcrypt для фактического выполнения шифрования. Я бы предложил использовать либо MCRYPT_BLOWFISHили MCRYPT_RIJNDAEL_128шифры и MCRYPT_MODE_CBCдля режима. Он достаточно сильный и достаточно быстрый (на моем компьютере цикл шифрования и дешифрования занимает около 1/2 секунды).

Теперь, что касается пункта 3 из первого списка, это даст вам такую ​​функцию:

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

Вы можете растянуть его в makeKey()функции, но так как он будет растянут позже, в этом нет особой необходимости.

Что касается размера хранилища, это зависит от простого текста. Blowfish использует 8-байтовый размер блока, поэтому у вас будет:

  • 16 байт для соли
  • 64 байта для hmac
  • длина данных
  • Заполнение так, чтобы длина данных% 8 == 0

Таким образом, для 16-символьного источника данных будет зашифровано 16 символов данных. Это означает, что фактический размер зашифрованных данных составляет 16 байтов из-за заполнения. Затем добавьте 16 байтов для соли и 64 байта для hmac, и общий сохраненный размер составит 96 байтов. Так что, в лучшем случае, накладные расходы в 80 символов, а в худшем - на 87 символов ...

Надеюсь, это поможет...

Примечание: 12/11/12: я только что обновил этот класс с НАМНОГО лучшим методом шифрования, используя лучшие производные ключи и исправив генерацию MAC ...

ircmaxell
источник
3
Кто-то не понимает, что значит «сломаться». @IRC хорошая работа в классе, это чертовски хороший код.
Jcolebrand
1
Следующее возвращает false. Есть идеи почему? $ x = новое шифрование (MCRYPT_BlOWFISH, MCRYPT_MODE_CBC); $ test = $ x-> encrypt ("test", "a"); echo var_dump ($ x-> decrypt ($ test, "a"));
Длина волны
2
Ох, и снова в функции дешифрования, изменяя два -64с, чтобы -128помочь (так вы получаете $enc = substr($data, 128, -128)и$mac = substr($data, -128);
космогорги
4
@ircmaxell Прошло довольно много времени с тех пор, как код последний раз пересматривался, поэтому мне интересно, не устарел ли он. Мне нужно использовать нечто подобное для финансового приложения, и было бы неплохо, если бы вы дали
добро на
2
Предупреждение! Расширение mcrypt было заброшено уже почти десять лет, и его было довольно сложно использовать. Поэтому он не рекомендуется в пользу OpenSSL, где он будет удален из ядра и в PECL в PHP 7.2. th1.php.net/manual/en/migration71.deprecated.php
ви
15

Как зашифровать и расшифровать пароль в PHP? Благодаря реализации одного из многих алгоритмов шифрования. (или используя одну из множества библиотек)

Какой алгоритм шифрования паролей является самым безопасным? Существует множество различных алгоритмов, ни один из которых не является на 100% безопасным. Но многие из них достаточно безопасны для коммерческих и даже военных целей

Где я могу хранить закрытый ключ? Если вы решили реализовать алгоритм криптографии с открытым ключом (например, RSA), вы не храните закрытый ключ. У пользователя есть закрытый ключ. ваша система имеет открытый ключ, который может храниться где угодно.

Вместо того, чтобы хранить закрытый ключ, стоит ли требовать, чтобы пользователи вводили закрытый ключ каждый раз, когда им нужен расшифрованный пароль? (Пользователям этого приложения можно доверять) Хорошо, если ваш пользователь может запоминать смехотворно длинные простые числа, тогда - да, почему бы и нет. Но, как правило, вам нужно создать систему, которая позволит пользователю хранить свой ключ где-нибудь.

Каким образом пароль может быть украден и расшифрован? Что мне нужно знать? Это зависит от используемого алгоритма. Однако всегда следите за тем, чтобы вы не отправляли незашифрованный пароль пользователю или от него. Либо зашифруйте / расшифруйте его на стороне клиента, либо используйте https (или используйте другие криптографические средства для защиты соединения между сервером и клиентом).

Однако, если все, что вам нужно, это хранить пароли в зашифрованном виде, я бы посоветовал вам использовать простой XOR-шифр. Основная проблема этого алгоритма состоит в том, что он может быть легко взломан частотным анализом. Однако, как правило, пароли не состоят из длинных абзацев английского текста, я не думаю, что вам следует беспокоиться об этом. Вторая проблема с XOR Cipher заключается в том, что если у вас есть сообщение в зашифрованном и зашифрованном виде, вы можете легко узнать пароль, с помощью которого оно было зашифровано. Опять же, не большая проблема в вашем случае, поскольку она затрагивает только пользователя, который уже был скомпрометирован другими способами.

Иван
источник
В ответе 3, когда вы говорите, что у пользователей есть закрытый ключ, я не понимаю, что это значит. Вы не рекомендуете передавать закрытые ключи в приложение вручную пользователем, так как же еще они передаются в приложение?
HyderA
Ну, это немного проблемы. Закрытый ключ можно сохранить в текстовом файле, а затем скопировать и вставить в приложение. Ключ также может храниться на сервере, но в этом случае он все равно должен быть зашифрован с помощью другого алгоритма шифрования, такого как XOR. Использование XOR здесь в этом случае является достаточно безопасным, поскольку существует только одна пара пароль-сообщение, а сообщение является довольно случайным, поэтому частотный анализ не может быть использован.
Иван
4
Я, конечно, не рекомендовал бы реализовывать алгоритм шифрования самостоятельно, слишком много потенциальных подводных камней, и многие люди протестировали и проанализировали существующие библиотеки.
Длинные уши
Основная проблема с XOR заключается в том, что если кто-то украл данные вашего приложения и знает только один из паролей пользователя, он может расшифровать все остальные пароли этого пользователя.
Длинные уши
1
@Ivan: да, но это один из случаев, когда я думаю, что DIY действительно очень плох, если вы ДЕЙСТВИТЕЛЬНО не понимаете криптографию. Существуют сильные шифры, почему бы не использовать их?
ircmaxell
13
  1. Вам нужна PHP-функция Mcrypt ( http://www.php.net/manual/en/intro.mcrypt.php ).

Пример из руководства немного отредактирован для этого примера):

<?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";
?>

Вы бы использовали mcrypt_decrypt для расшифровки вашего пароля.

  1. Лучший алгоритм довольно субъективен - спросите 5 человек, получите 5 ответов. Лично, если значение по умолчанию (Blowfish) не достаточно для вас, у вас, вероятно, есть большие проблемы!

  2. Учитывая, что PHP необходим для шифрования - не уверен, что вы можете спрятать его где-либо - приветствуйте комментарии по этому поводу. Стандартные PHP лучшие практики кодирования применяются конечно!

  3. Учитывая, что ключ шифрования будет в вашем коде в любом случае, не уверен, что вы получите, при условии, что остальная часть вашего приложения в безопасности.

  4. Очевидно, что если зашифрованный пароль и ключ шифрования украдены, то игра окончена.

Я бы поставил на ответ гонщика - я не эксперт по криптографии PHP, но я думаю, что я ответил, что это стандартная практика - я приветствую комментарии, которые могут быть у других.

Джон Роудс
источник
$pass = $text, Я думаю, что он изменил это, чтобы удовлетворить вопрос, и не заметил второго случая.
HyderA
3
Две вещи на заметку. Во-первых, MCRYPT_MODE_ECBне использует IV. Во-вторых, если это произойдет, вам нужно будет сохранить IV, поскольку вы не сможете расшифровать данные без него ...
ircmaxell
«Лучший алгоритм довольно субъективен - спросите 5 человек, получите 5 ответов. Лично, если значение по умолчанию (Blowfish) недостаточно для вас, у вас, вероятно, большие проблемы!» Это совершенно неправильно. Любой криптоэксперт будет более или менее согласен с gist.github.com/tqbf/be58d2d39690c3b366ad, который специально исключает раздувную рыбу
Скотт Аркишевский
6

Многие пользователи предлагают использовать mcrypt ... это правильно, но я хотел бы пойти дальше, чтобы его было легко хранить и передавать (поскольку иногда зашифрованные значения могут затруднить их отправку с использованием других технологий, таких как curl или json) ,

После того как вы успешно зашифровали с помощью mcrypt, запустите его через base64_encode и затем преобразуйте его в шестнадцатеричный код. Однажды в шестнадцатеричном коде это легко передать различными способами.

$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));

А с другой стороны:

$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);
Брэдли
источник
Макрипт не лучший вариант
Скотт Аркишевский
2
Хорошо - это было в 2011 году: P
Брэдли
5

Я бы рекомендовал шифрование с открытым ключом только в том случае, если вы хотите установить пароль пользователя без его взаимодействия (это может быть удобно для сброса и общих паролей).

Открытый ключ

  1. Расширение OpenSSL , в частности openssl_public_encryptиopenssl_private_decrypt
  2. Это был бы прямой RSA, предполагая, что ваши пароли будут соответствовать размеру ключа - заполнение, в противном случае вам нужен симметричный слой
  3. Сохраните оба ключа для каждого пользователя, пароль личного ключа - это пароль его приложения

симметричный

  1. Mcrypt расширение
  2. AES-256, вероятно, безопасная ставка, но сам по себе этот вопрос может быть
  3. Вы не - это будет их пароль приложения

Обе

4, Да - пользователям придется каждый раз вводить пароль своего приложения, но сохранение его в сеансе вызовет другие проблемы

5,

  • Если кто-то крадет данные приложения, он так же безопасен, как и симметричный шифр (для схемы с открытым ключом он используется для защиты секретного ключа с помощью ключевой фразы).
  • Ваше приложение определенно должно быть доступно только через SSL, предпочтительно с использованием клиентских сертификатов.
  • Рассмотрите возможность добавления второго фактора для аутентификации, который будет использоваться только один раз за сеанс, например, токен, отправляемый через SMS.
Длинные уши
источник
Избегайте mcrypt, будьте осторожны с openssl_private_decrypt().
Скотт Аркишевский
2

Я пробовал что-то вроде этого, но, пожалуйста, обратите внимание, что я не криптограф и не обладаю глубокими знаниями phpили каким-либо языком программирования. Это просто идея. Моя идея состоит в том, чтобы сохранить keyв каком-либо файле или database(или ввести вручную), какое (местоположение) не может быть легко предсказано (и, конечно, когда-нибудь что-нибудь будет расшифровано, концепция состоит в том, чтобы увеличить время дешифрования) и зашифровать конфиденциальную информацию.

$iv_size = mcrypt_get_iv_size(MCRYPT_BLOWFISH , MCRYPT_MODE_ECB);
$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
$key = "evenifyouaccessmydatabaseyouwillneverfindmyemail";
$text = "myemail@domain.com";
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.

Обратите внимание, что это просто концепция. Любое улучшение в этом коде было бы весьма заметно.

Сантош Линкха
источник
2

Пароли предназначены для аппаратного устройства, поэтому о проверке хешей не может быть и речи

А? Я не понимаю Вы имеете в виду, что пароль должен быть восстановим?

Как уже говорили другие, расширение mcrypt предоставляет доступ ко многим криптографическим функциям - однако вы предлагаете своим пользователям положить все свои яйца в одну корзину - ту, которая потенциально может стать целью для злоумышленников - и если вы даже не знаете как начать решать проблему, тогда вы оказываете своим пользователям медвежью услугу. Вы не в состоянии понять, как защитить данные.

Большинство уязвимостей безопасности возникают не потому, что лежащий в основе алгоритм ошибочен или небезопасен, а из-за проблем с тем, как алгоритм используется в коде приложения.

Сказав это, можно построить достаточно безопасную систему.

Асимметричное шифрование следует рассматривать только в том случае, если у пользователя есть требование создать защищенное сообщение, которое может прочитать другой (определенный) пользователь. Причина в том, что это вычислительно дорого. Если вы просто хотите предоставить пользователям репозиторий для ввода и извлечения собственных данных, симметричное шифрование является адекватным.

Однако если вы храните ключ для расшифровки сообщения в том же месте, что и зашифрованное сообщение (или там, где хранится зашифрованное сообщение), то система не защищена. Используйте тот же токен для аутентификации пользователя, что и для ключа дешифрования (или в случае асимметричного шифрования используйте токен в качестве секретной фразы секретного ключа). Поскольку вам нужно будет сохранить токен на сервере, где дешифрование происходит, по крайней мере, временно, вы можете рассмотреть возможность использования субстрата хранения сеанса без возможности поиска или передачи токена непосредственно демону, связанному с сеансом, который будет хранить токен в памяти и выполнять расшифровку сообщений по требованию.

symcbean
источник
1

Используйте password_hash и 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";
?>

И расшифровать

<?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
источник