Безопасный обмен ключами с libsodium

Я хочу сделать тестовое приложение, которое использует libsodium для связи от клиента к серверу.

Есть много портов для многих языков: C#, PHP,...

и всегда есть пример с "Боб" и "Алиса". Это нормально, но они никогда не показывают, как безопасно обмениваться открытыми ключами по сети.

Так как же рекомендовать способ обмена открытыми ключами для "Алиса / клиент" и "Боб / сервер".

Они всегда используют один и тот же файл или один и тот же компьютер для генерации пар ключей.

Вот выдержка из расширения libsodium-php:

$alice_kp = crypto_box_keypair();
$alice_secretkey = crypto_box_secretkey($alice_kp);
$alice_publickey = crypto_box_publickey($alice_kp);

$bob_kp = crypto_box_keypair();
$bob_secretkey = crypto_box_secretkey($bob_kp);
$bob_publickey = crypto_box_publickey($bob_kp);

$alice_to_bob_kp = crypto_box_keypair_from_secretkey_and_publickey
  ($alice_secretkey, $bob_publickey);

$bob_to_alice_kp = crypto_box_keypair_from_secretkey_and_publickey
  ($bob_secretkey, $alice_publickey);

$alice_to_bob_message_nonce = randombytes_buf(CRYPTO_BOX_NONCEBYTES);

$alice_to_bob_ciphertext = crypto_box('Hi, this is Alice',
                                      $alice_to_bob_message_nonce,
                                      $alice_to_bob_kp);

$alice_message_decrypted_by_bob = crypto_box_open($alice_to_bob_ciphertext,
                                                  $alice_to_bob_message_nonce,
                                                  $bob_to_alice_kp);

$bob_to_alice_message_nonce = randombytes_buf(CRYPTO_BOX_NONCEBYTES);

$bob_to_alice_ciphertext = crypto_box('Hi Alice! This is Bob',
                                      $bob_to_alice_message_nonce,
                                      $bob_to_alice_kp);

$bob_message_decrypted_by_alice = crypto_box_open($bob_to_alice_ciphertext,
                                                  $bob_to_alice_message_nonce,
                                                  $alice_to_bob_kp);

1 ответ

Решение

Libsodium не предоставляет прямых методов обмена ключами. Вы можете безопасно обменяться ключами несколькими способами:

  1. Посредством защищенной от несанкционированного доступа "внеполосной связи" доставьте открытый ключ или, если ком-канал защищен от слушателей, общий секрет. (например, BittorrentSync, QR-код, содержащий общий секрет, который сканируется с устройства на устройство)

  2. Попросите доверенную третью сторону подписать открытые ключи перед их отправкой в ​​незашифрованном виде. (напр. Центры сертификации в SSL/TLS)

  3. Закрепление сертификатов (например, Google Chrome для URL-адресов Google)

Если вы контролируете клиента

Поскольку вы, вероятно, не хотите повторно внедрять SSL / TLS, первый или третий вариант, вероятно, будет лучшим. Однако первое довольно сложно в формате клиент / сервер, поскольку сервер PHP, вероятно, имеет только Интернет для связи.

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

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

Боб использует полученный им открытый ключ и собственный закрытый ключ для расшифровки и проверки зашифрованного пакета. Для Боба было бы безопасно использовать любые данные внутри, так как только он и Алиса могут расшифровать их.

Как насчет человека посередине?

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

В глазах Боба она будет просто еще одним клиентом. В глазах Алисы она расстроится, потому что Боб, похоже, не отвечает.

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

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

Примечание об утечке закрытых ключей см. В последнем разделе этого ответа.

Защита от взлома

Вы можете разместить QR-код на веб-сайте по протоколу HTTPS после того, как пользователь клиента каким-либо образом подтвердил свою подлинность (с помощью некоторого пользовательского пароля или, возможно, в будущем, используя SQRL). QR-код показывает, что клиент может сканировать или ссылку с пользовательский протокол путем регистрации себя в ОС в качестве обработчика для этого протокола URI.

Менее сложная альтернатива вышеуказанному методу QR-кода / uri будет состоять в том, чтобы просто скопировать и вставить общий секретный ключ с вышеупомянутого HTTPS-сайта, который будет использоваться для первоначального обмена открытым ключом с помощью метода crypto_secretbox() натрия.

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

Что делать, если утечка секретного ключа сервера?

Если вам нужна прямая секретность в случае утечки частного ключа, то исходную пару открытого / закрытого ключа следует использовать только для обмена вторым циклом открытых ключей, которые никогда не сохраняются на постоянном носителе (по сути, без диска или базы данных).). Поскольку ваше дело - только тестовое приложение, Forward Secrecy может быть не очень важным.

Второй раунд ключей отбрасывается очень часто (как каждые 24 часа), уменьшая риски для прошлых данных стать уязвимыми из-за ошибок, таких как Heartbleed OpenSSL.

В традиционном использовании PHP веб-сервера это может быть трудно сделать, поскольку все переменные сбрасываются для каждого HTTP-запроса. Правильно настроенный экземпляр memcached может быть вариантом, но есть риск утечки временных закрытых ключей.

Другие вопросы по тегам