Какой алгоритм шифрования лучше всего подходит для шифрования файлов cookie? - PullRequest
47 голосов
/ 03 марта 2009

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

Позвольте мне подчеркнуть правильный ответ , заданный AviD на этот вопрос:

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



Я ищу информацию о «лучшем» алгоритме шифрования для шифрования файлов cookie.

У меня есть следующие требования:

  • Должно быть быстро
    шифрование и дешифрование данных будут выполняться для (почти) каждого запроса

  • Он будет работать с небольшими наборами данных, обычно со строками длиной около 100 символов или менее

  • Это должно быть безопасно, но мы не защищаем банковские операции

  • Мы должны иметь возможность расшифровать информацию, чтобы SHA1 и т. П. Вышли.

Теперь я прочитал, что Blowfish быстр и безопасен, и я прочитал, что AES быстр и безопасен. С Blowfish, имеющим меньший размер блока.

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

Итак, мой вопрос:
Какой алгоритм шифрования лучше всего подходит для шифрования данных cookie?

Обновление
Точнее, мы хотим зашифровать 2 куки: один с информацией о сеансе, а другой с информацией «запомни меня».

Платформа представляет собой PHP как модуль apache в Linux на VPS.

Обновление 2
Я согласен с cletus , что хранение любой информации в cookie-файле небезопасно.

Однако у нас есть требование для реализации функции «запомни меня». Принятый способ сделать это - установить cookie. Если клиент представляет этот файл cookie, ему или ей разрешается доступ к системе с (почти) равными правами, как если бы он представил действительную комбинацию пароля пользователя.

Итак, мы по крайней мере хотим зашифровать все данные в куки, чтобы они:
a) злоумышленники не могут прочитать его содержимое,
b) злоумышленники не могут изготовить свой собственный файл cookie или вмешаться в него.

(Все данные из файлов cookie очищаются и проверяются на достоверность, прежде чем мы что-то с ними делаем, но это уже другая история)

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

Итак, учитывая, что нам необходимо сохранить некоторые данные в файле cookie, как лучше всего их зашифровать?

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

Однако я тоже в растерянности:
Я думал, что шифрование позволяет нам отправлять данные в BigBadWorld & trade; и все еще быть (достаточно) уверенным, что никто не сможет их прочитать или подделать ...
Разве это не весь смысл шифрования?

Но реакция ниже подталкивает к: Не доверяйте шифрованию для обеспечения безопасности.

Чего мне не хватает ??

Ответы [ 12 ]

24 голосов
/ 03 марта 2009

Нет реальной причины не использовать AES с 256 битами. Обязательно используйте это в режиме CBC и заполнении PKCS # 7. Как вы сказали, быстро и безопасно.

Я прочитал (не проверял), что Blowfish может быть немного быстрее ... Однако у Blowfish есть существенный недостаток - длительное время установки, что может ухудшить вашу ситуацию. Также AES более «проверен».

Предполагается, что действительно необходимо для симметричного шифрования данных cookie. Как уже отмечали другие, это действительно не должно быть необходимым, и есть только несколько крайних случаев, когда нет другого выбора, кроме как сделать это. Как правило, лучше было бы изменить дизайн и вернуться либо к произвольным идентификаторам сеансов, либо, если необходимо, к односторонним хэшам (с использованием SHA-256).
В вашем случае, помимо «обычного» случайного идентификатора сеанса, ваша проблема - это функция «запомнить меня» - это также должно быть реализовано так:

  • длинное случайное число, хранящееся в базе данных и сопоставленное с учетной записью пользователя;
  • или хэш-ключ с ключом (например, HMAC), содержащий, например, имя пользователя, временная метка, mebbe соль и секретный ключ сервера. Конечно, все это можно проверить на стороне сервера ...

Похоже, мы немного отошли от темы вашего оригинального, конкретного вопроса - и изменили основу вашего вопроса, изменив дизайн ....
Поэтому, пока мы это делаем, я также настоятельно рекомендую ПРОТИВ эту особенность постоянного «запомни меня» по нескольким причинам, самая большая из них:

  • Повышает вероятность того, что кто-то может украсть ключ запоминания этого пользователя, что позволит ему подделать личность пользователя (а затем, вероятно, сменить его пароль);
  • CSRF - Подделка межсайтовых запросов . Ваша функция позволит анонимному злоумышленнику заставить неосведомленных пользователей отправлять «аутентифицированные» запросы в ваше приложение, даже не входя в систему.
19 голосов
/ 03 марта 2009

Это касается двух отдельных вопросов.

Во-первых, угон сеанса . Именно здесь третья сторона обнаруживает, скажем, аутентифицированный файл cookie и получает доступ к чужим данным.

Во-вторых, безопасность данных сеанса . Под этим я подразумеваю, что вы храните данные в куки (например, имя пользователя). Это не очень хорошая идея. Любые такие данные принципиально ненадежны, так же как данные форм HTML ненадежны (независимо от того, какие проверки Javascript и / или ограничения длины HTML вы используете, если таковые имеются), потому что клиент может свободно отправлять то, что он хочет.

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

Если вы намереваетесь сохранить данные в cookie-файле, я настоятельно рекомендую вам пересмотреть.

Шифрование этих данных не делает информацию более надежной, поскольку симметричное шифрование подвержено атаке методом перебора. Очевидно, что AES-256 лучше, чем, скажем, DES (хех), но 256-битная защита не обязательно означает столько, сколько вы думаете.

С одной стороны, СОЛЬ, как правило, генерируются в соответствии с алгоритмом или иным образом подвержены атакам.

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

Это возвращает нас к первому пункту: угон.

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

Примечание: вышеописанное не является уникальным для PHP.

Но это шифрование на стороне сервера.

Теперь вы можете утверждать, что шифрование сеанса с некоторыми дополнительными данными сделает его более безопасным от угона. Типичным примером является IP-адрес пользователя. Проблема в том, что многие люди используют один и тот же ПК / ноутбук в разных местах (например, в точках доступа Wi-Fi, на работе, дома). Также многие среды будут использовать различные IP-адреса в качестве адреса источника, особенно в корпоративных средах.

Вы также можете использовать пользовательский агент, но это предположительно.

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

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

Я с радостью ошибусь, если кто-то укажет на что-то обратное.

9 голосов
/ 25 октября 2010

Предупреждение безопасности : эти две функции не являются безопасными. Они используют режим ECB и не могут аутентифицировать шифротекст . См. этот ответ для лучшего пути вперед.

Для читателей, желающих использовать этот метод в сценариях PHP. Вот рабочий пример использования 256-битного Rijndael (не AES).

function encrypt($text, $salt) 
{ 
    return trim(base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $salt, $text, MCRYPT_MODE_ECB, mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB), MCRYPT_RAND)))); 
} 

function decrypt($text, $salt) 
{ 
    return trim(mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $salt, base64_decode($text), MCRYPT_MODE_ECB, mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB), MCRYPT_RAND))); 
}

Затем сохранить куки

setcookie("PHPSESSION", encrypt('thecookiedata', 'longsecretsalt'));

и прочитать на следующей странице:

$data = decrypt($_COOKIE['PHPSESSION'], 'longsecretsalt');
4 голосов
/ 30 июля 2015

быстрое зашифрованное печенье с Libsodium

Если вам нужны быстрые и безопасные зашифрованные куки в PHP, посмотрите, как Halite реализует их. Halite использует расширение PECL libsodium для обеспечения безопасной криптографии.

<?php
use \ParagonIE\Halite\Cookie;
use \ParagonIE\Halite\Symmetric\Key;
use \ParagonIE\Halite\Symmetric\SecretKey;

// You can also use Key::deriveFromPassword($password, $salt, Key::CRYPTO_SECRETBOX);
$encryption_key = new SecretKey($some_constant_32byte_string_here);

$cookie = new Cookie($encryption_key);

$cookie->store('index', $any_value);
$some_value = $cookie->fetch('other_index');

Если вы не можете установить расширения PECL, попросите вашего системного администратора или хостинг-провайдера сделать это за вас. Если они откажутся, у вас все еще есть варианты.


Безопасные зашифрованные куки в PHP, пожалуйста, держите соль

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

При использовании расширения OpenSSL процесс, которому вы должны будете следовать, выглядит следующим образом:


Преамбула

  • (еще до того, как вы задумаетесь о шифровании). Создайте 128-битную, 192-битную или 256-битную случайную строку. Это будет ваш мастер-ключ .

    Не используйте читабельный пароль. Если по какой-то причине должен использовать читабельный пароль, попросите Cryptography SE для получения руководства .

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

Шифрование

  1. Генерация случайного вектора инициализации (IV) или одноразового номера. например random_bytes(openssl_cipher_iv_length('aes-256-cbc'))
  2. Используйте HKDF или аналогичный алгоритм для разделения вашего мастер-ключа на два ключа:
    1. Ключ шифрования ($eKey)
    2. Ключ аутентификации ($aKey)
  3. Зашифруйте вашу строку с помощью openssl_encrypt() с вашим IV и соответствующим модатом (например, aes-256-ctr), используя ваш ключ шифрования ($eKey) из шага 2.
  4. Вычислите тег аутентификации вашего зашифрованного текста из шага 3, используя ключевую хеш-функцию, такую ​​как HMAC-SHA256. например hash_hmac('sha256', $iv.$ciphertext, $aKey). Очень важно аутентифицироваться после шифрования, а также инкапсулировать IV / nonce.
  5. Упакуйте тег аутентификации, IV или nonce и зашифрованный текст вместе и при желании закодируйте его с помощью bin2hex() или base64_encode(). (Предупреждение. При таком подходе может утечка информации о времени кэширования.)

дешифрование

  1. Разделите ваш ключ согласно шагу 2 в шифровании. Нам нужны те же две клавиши во время расшифровки!
  2. (Опционально, декодировать и) распаковать MAC, IV и зашифрованный текст из упакованного сообщения.
  3. Проверьте тег аутентификации, пересчитав HMAC IV / nonce и зашифрованный текст с HMAC, предоставленным пользователем, используя hash_equals().
  4. Если и только если пройден шаг 3, расшифруйте зашифрованный текст, используя $eKey.

Если вы хотите увидеть, как все это выглядит вместе, посмотрите этот ответ с примером кода .

Если это звучит как слишком много работы, используйте defuse / php-encryption или zend-crypt и называйте это днем.


Помни меня, печенье

Однако у нас есть требование для реализации функции «запомни меня». Принятый способ сделать это - установить cookie. Если клиент представляет этот файл cookie, ему или ей разрешается доступ к системе с (почти) равными правами, как если бы он представил действительную комбинацию пароля пользователя.

Шифрование на самом деле не подходит для этой работы. Вы хотите выполнить этот процесс для безопасных файлов cookie помните меня в PHP :

Создание токена Remember Me

  1. Генерация двух случайных строк:
    1. A selector, который будет использоваться для поиска в базе данных. (Цель случайного селектора вместо простого последовательного идентификатора - , а не утечка информации о количестве активных пользователей на вашем веб-сайте. Если вам удобно передавать эту информацию, не стесняйтесь использовать только последовательный идентификатор. )
    2. A validator, который будет использоваться для автоматической аутентификации пользователя.
  2. Рассчитать хеш validator (достаточно простого хеша SHA-256).
  3. Сохраните selector и хэш validator в таблице базы данных, зарезервированной для автоматического входа.
  4. Сохраните selector и validator в файле cookie на клиенте.

Погашение жетона "Помни меня"

  1. Разделить входящий файл cookie на selector и validator.
  2. Выполнить поиск в базе данных (используйте подготовленные операторы !) На основе selector.
  3. Если строка найдена, вычислите хеш validator.
  4. Сравните хеш, вычисленный на шаге 3, с хешем, сохраненным в базе данных, еще раз, используя hash_equals().
  5. Если шаг 4 возвращает true, войдите в систему с соответствующей учетной записью.

Это стратегия, принятая Gatekeeper для долгосрочной аутентификации пользователей, и это наиболее безопасная стратегия, предложенная на сегодняшний день для удовлетворения этого требования.

4 голосов
/ 23 сентября 2009

Вы можете безопасно достичь желаемого с помощью AES в режиме EAX. Зашифрованный текст будет больше, чем открытый текст; это нормально для безопасного шифрования.

Злоумышленник, конечно, будет знать длину вашего открытого текста из зашифрованного текста, но он не сможет определить что-либо еще.

Генерация ключей AES случайным образом.

Убедитесь, что для каждого шифрования используется новый одноразовый номер, и используйте поле «связанные данные», чтобы гарантировать, что вещь, которую вы зашифровали для одной цели, не представлена ​​как предназначенная для другой (например, такие как имя пользователя и имя файла cookie). мог бы пойти туда)

Реакция ниже подталкивает к: Do не доверять шифрованию для достижения безопасность.

Подробнее "Если вы не специалист по шифрованию, вы недооцените, насколько легко ошибиться". Например, AFAICT никто другой в этой теме не обсуждал режимы цепочки или целостность сообщений, которые охватывают две распространенные ошибки новичка.

2 голосов
/ 29 октября 2013

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

Особенно мир PHP полон плохих примеров, которые игнорируют это (см. Криптография PHP - действуйте осторожно ), но это применимо к любому языку.

Один из немногих хороших примеров, которые я видел, это PHP-CryptLib , который использует комбинированный режим шифрования-аутентификации для выполнения этой работы. Для Python pyOCB предлагает аналогичные функции.

2 голосов
/ 12 октября 2009

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

Я считаю, что реальная проблема, связанная с кражей ваших файлов cookie, - это связь между сервером и клиентом. Используйте SSL-соединение, предоставленное вашим хостом.

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

2 голосов
/ 03 марта 2009

Хотя оба очень сильные, AES является стандартом.

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

1 голос
/ 03 марта 2009

Почему вы хотите зашифровать куки?

На мой взгляд, есть два случая: либо вы даете клиенту ключ, либо нет.

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

Если вы действительно вручаете клиенту ключ, то зачем вам его в первую очередь шифровать? Если вы не шифруете передачу ключа, то шифрование cookie является спорным: MITM может посмотреть файл cookie и отправить вам любой файл cookie, который он хочет. Если вы используете зашифрованный канал для клиента, зачем использовать шифрование хранимых данных?

Если вы беспокоитесь о том, что другие пользователи на клиентском компьютере читают куки, сдавайтесь и предположите, что браузер устанавливает хорошие биты прав:)

0 голосов
/ 14 марта 2011

Кроме того, я попробовал mcrypt_encrypt, и помните одну вещь. Если вы делаете base64_encode(mcrypt_encrypt(...)).

, а затем вы делаете base64_decode и выводите зашифрованные данные (echo). Вы наверняка облажаетесь и ничего не видите. Однако, если вы делаете mcrypt_decrypt( ... base64_decode($value) ). Вы увидите исходные данные.

...