Какой алгоритм шифрования лучше всего подходит для шифрования файлов cookie?
Поскольку этот вопрос довольно популярен, я подумал, что полезно обновить его.
Позвольте мне подчеркнуть правильный ответ, данный John на этот вопрос:
Вы не должны хранить какие-либо данные, которые должны быть зашифрованы в вашем cookie. Вместо этого сохраните случайный ключ (128 бит /16 байт) в файле cookie и сохраните информацию, которую вы хотите защитить, на сервере, идентифицированную ключом файла cookie.
Я ищу информацию о "лучшем" алгоритме шифрования для шифрования файлов cookie.
У меня есть следующие требования:
Должно быть быстро
шифрование и дешифрование данных будут выполняться для (почти) каждого запросаОн будет работать с небольшими наборами данных, обычно со строками длиной около 100 символов
Это должно быть безопасно, но это не так, как мы защищаем банковские операции
Мы должны иметь возможность расшифровать информацию, чтобы SHA1 и тому подобное вышли.
Теперь я прочитал, что Blowfish быстр и безопасен, и я прочитал, что AES быстр и безопасен. С Blowfish, имеющим меньший размер блока.
Я думаю, что оба алгоритма обеспечивают более чем адекватную безопасность? таким образом, скорость станет решающим фактором. Но я действительно понятия не имею, подходят ли эти алгоритмы для маленькой строки символов и, возможно, есть более подходящий алгоритм для шифрования файлов cookie.
Итак, мой вопрос:
Какой алгоритм шифрования лучше всего подходит для шифрования данных cookie?
Обновить
Чтобы быть более точным, мы хотим зашифровать 2 cookie: один с информацией о сеансе, а другой с информацией "запомни меня".
Платформа представляет собой PHP как модуль apache в Linux на VPS.
Обновление 2
Я согласен с cletus, что хранение любой информации в cookie- cletus небезопасно.
Однако у нас есть требование для реализации функции "запомни меня". Принятый способ сделать это - установить cookie. Если клиент представляет этот файл cookie, ему или ей предоставляется доступ к системе с (почти) равными правами, как если бы он представил действительную комбинацию пароля пользователя.
Поэтому мы по крайней мере хотим зашифровать все данные в куки, чтобы он:
а) злоумышленники не могут прочитать его содержимое,
б) злоумышленники не могут сфабриковать свой собственный файл cookie или взломать его.
(Все данные из файлов cookie очищаются и проверяются на достоверность, прежде чем мы что-то с ними делаем, но это уже другая история)
Файл cookie сеанса не содержит ничего из sessionId / timestamp. Возможно, его можно использовать без шифрования, но я не вижу вреда в его шифровании? (кроме времени вычисления).
Итак, учитывая, что мы должны хранить некоторые данные в cookie-файлах, как лучше всего их зашифровать?
Обновление 3
Ответы на этот вопрос заставили меня пересмотреть выбранный подход. Я действительно могу сделать то же самое без необходимости шифрования. Вместо того, чтобы шифровать данные, я должен только отправлять данные, которые не имеют смысла без их контекста и не могут быть угаданы.
Тем не менее, я также в растерянности:
Я думал, что шифрование позволило нам отправлять данные в BigBadWorld™, и все еще (достаточно) был уверен, что никто не сможет прочитать или подделать его...
Разве это не весь смысл шифрования?
Но реакция ниже подталкивает к: Не доверяйте шифрованию для обеспечения безопасности.
Что мне не хватает??
12 ответов
Нет реальной причины не использовать AES с 256 битами. Убедитесь, что используете это в режиме CBC и дополнении PKCS#7. Как вы сказали, быстро и безопасно.
Я читал (не проверял), что Blowfish может быть немного быстрее... Однако у Blowfish есть существенный недостаток - длительное время установки, что может ухудшить вашу ситуацию. Также AES более "проверен".
Это предполагает, что действительно необходимо симметрично зашифровать данные cookie. Как уже отмечали другие, это действительно не должно быть необходимым, и есть только несколько крайних случаев, когда нет другого выбора, кроме как сделать это. Как правило, лучше будет изменить дизайн и вернуться либо к произвольным идентификаторам сеансов, либо, если необходимо, к односторонним хэшам (с использованием SHA-256).
В вашем случае, помимо "обычного" случайного идентификатора сеанса, ваша проблема - это функция "запомнить меня" - это также должно быть реализовано так:
- длинное случайное число, хранящееся в базе данных и сопоставленное с учетной записью пользователя;
- или хеш с ключами (например, HMAC), содержащий, например, имя пользователя, временную метку, mebbe соль и ключ секретного сервера. Конечно, все это можно проверить на стороне сервера...
Похоже, мы немного отошли от темы вашего оригинального, конкретного вопроса - и изменили основу вашего вопроса, изменив дизайн....
Поэтому, пока мы делаем это, я также настоятельно рекомендую ПРОТИВ этой функции постоянного "помни меня" по нескольким причинам, самая большая из них:
- Повышает вероятность того, что кто-то может украсть ключ запоминания этого пользователя, что позволит ему подделать личность пользователя (а затем, вероятно, сменить его пароль);
- CSRF - Подделка межсайтовых запросов. Ваша функция позволит анонимному злоумышленнику заставить неосведомленных пользователей отправлять "аутентифицированные" запросы в ваше приложение, даже не входя в систему.
Это касается двух отдельных вопросов.
Во-первых, угон сеанса. Именно здесь третья сторона обнаруживает, скажем, аутентифицированный файл cookie и получает доступ к чужой информации.
Во-вторых, существует безопасность данных сеанса. Под этим я подразумеваю, что вы храните данные в куки (например, имя пользователя). Это не очень хорошая идея. Любые такие данные принципиально ненадежны, так же как и данные форм HTML не заслуживают доверия (независимо от того, какие проверки Javascript и / или ограничения длины HTML вы используете, если таковые имеются), потому что клиент может предоставить то, что он хочет.
Вы часто найдете людей (справедливо) выступающих за дезинфекцию данных HTML-форм, но данные cookie будут приниматься вслепую по номинальной стоимости. Большая ошибка. На самом деле, я никогда не храню информацию в куки. Я рассматриваю это как ключ сеанса, и это все.
Если вы намереваетесь хранить данные в файле cookie, я настоятельно рекомендую вам пересмотреть.
Шифрование этих данных не делает информацию более надежной, потому что симметричное шифрование подвержено атакам методом перебора. Очевидно, что AES-256 лучше, чем, скажем, DES (хех), но 256-битная защита не обязательно означает столько, сколько вы думаете.
С одной стороны, ОСВ обычно генерируются в соответствии с алгоритмом или иным образом подвержены атаке.
С другой стороны, данные cookie являются основным кандидатом для атак в хлевах. Если известно или подозревается, что имя пользователя находится в зашифрованных данных, то это будет ваша кроватка.
Это возвращает нас к первому пункту: угон.
Следует отметить, что в средах общего хостинга в PHP (в качестве одного примера) ваши данные сеанса просто хранятся в файловой системе и могут быть прочитаны кем-либо еще на этом же хосте, хотя они не обязательно знают, для какого сайта он предназначен. Поэтому никогда не храните незашифрованные пароли, номера кредитных карт, обширные личные данные или что-либо, что могло бы считаться конфиденциальным в данных сеанса в таких средах без какой-либо формы шифрования или, что еще лучше, просто сохраняя ключ в сеансе и сохраняя фактический конфиденциальный данные в базе данных.
Примечание: вышеупомянутое не уникально для PHP.
Но это шифрование на стороне сервера.
Теперь вы можете утверждать, что шифрование сеанса с некоторыми дополнительными данными сделает его более безопасным от взлома. Типичным примером является IP-адрес пользователя. Проблема в том, что многие люди используют один и тот же ПК / ноутбук в разных местах (например, в точках доступа Wi-Fi, на работе, дома). Также многие среды будут использовать различные IP-адреса в качестве адреса источника, особенно в корпоративных средах.
Вы также можете использовать пользовательский агент, но это предположительно.
На самом деле, насколько я могу судить, нет никакой реальной причины использовать шифрование cookie вообще. Я никогда не думал, что был, но в свете этого вопроса я пытался доказать, что он прав или нет. Я обнаружил несколько потоков о людях, предлагающих способы шифрования данных cookie, прозрачного выполнения этого с помощью модулей Apache и т. Д., Но все это, кажется, мотивировано защитой данных, хранящихся в cookie (что, я думаю, не следует делать).
Я еще не видел аргумента безопасности для шифрования куки, который представляет собой не что иное, как сеансовый ключ.
Я с радостью окажусь неправ, если кто-то укажет на что-то обратное.
Предупреждение безопасности: эти две функции не являются безопасными. Они используют режим 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');
Быстрое зашифрованное печенье с Libsodium
Если вам нужны быстрые и безопасные зашифрованные куки в PHP, посмотрите, как Halite реализует их. Halite использует расширение libsodium PECL для обеспечения безопасной криптографии.
<?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.
Если вам нужно особое внимание, мой работодатель предлагает услуги по технологическому консалтингу, включая разработку функций криптографии.
шифрование
- Генерация случайного вектора инициализации (IV) или одноразового номера. например
random_bytes(openssl_cipher_iv_length('aes-256-cbc'))
- Используйте HKDF или аналогичный алгоритм для разделения вашего мастер-ключа на два ключа:
- Ключ шифрования (
$eKey
) - Ключ аутентификации (
$aKey
)
- Ключ шифрования (
- Зашифруйте вашу строку с
openssl_encrypt()
с вашим IV и соответствующим модатом (например,aes-256-ctr
) используя ваш ключ шифрования ($eKey
) из шага 2. - Вычислите тег аутентификации вашего зашифрованного текста из шага 3, используя ключевую хеш-функцию, такую как HMAC-SHA256. например
hash_hmac('sha256', $iv.$ciphertext, $aKey)
, Это очень важно для аутентификации после шифрования, а также для инкапсуляции IV/nonce. - Упакуйте тег аутентификации, IV или nonce и зашифрованный текст вместе и при необходимости закодируйте его
bin2hex()
или жеbase64_encode()
, (Предупреждение: этот подход может привести к утечке информации о времени кэширования.)
Дешифрирование
- Разделите ваш ключ согласно шагу 2 в шифровании. Нам нужны те же два ключа во время расшифровки!
- (Опционально, декодировать и) распаковать MAC, IV и зашифрованный текст из упакованного сообщения.
- Проверьте тег аутентификации, пересчитав HMAC IV/nonce и зашифрованный текст с HMAC, предоставленным пользователем, используя
hash_equals()
, - Если и только если пройден шаг 3, расшифруйте зашифрованный текст, используя
$eKey
,
Если вы хотите увидеть, как все это выглядит вместе, посмотрите ответ, содержащий пример кода.
Если это звучит как слишком много работы, используйте https://github.com/defuse/php-encryption или zend-crypt и называйте это днем.
Запомнить меня Печенье
Однако у нас есть требование для реализации функции "запомни меня". Принятый способ сделать это - установить cookie. Если клиент представляет этот файл cookie, ему или ей предоставляется доступ к системе с (почти) равными правами, как если бы он представил действительную комбинацию пароля пользователя.
Шифрование на самом деле не является правильным инструментом для этой работы. Вы хотите следовать этому процессу для безопасного сохранения файлов cookie в PHP:
Создание токена "Помни меня"
- Генерация двух случайных строк:
-
selector
который будет использоваться для поиска в базе данных. (Цель случайного селектора вместо простого последовательного идентификатора состоит в том, чтобы не пропускать количество активных пользователей на вашем веб-сайте. Если вам удобно передавать эту информацию, не стесняйтесь просто использовать последовательный идентификатор.) -
validator
который будет использоваться для автоматической аутентификации пользователя.
-
- Рассчитать хеш
validator
(достаточно простого хэша SHA-256). - Хранить
selector
и хэшvalidator
в таблице базы данных, зарезервированной для автоматического входа. - Хранить
selector
а такжеvalidator
в куки на клиенте.
Выкуп жетона "Помни меня"
- Разбить входящие куки в
selector
а такжеvalidator
, - Выполните поиск в базе данных (используйте подготовленные операторы!) На основе
selector
, - Если строка найдена, вычислите хеш
validator
, - Сравните хеш, вычисленный на шаге 3, с хешем, хранящимся в базе данных, еще раз, используя
hash_equals()
, - Если шаг 4 возвращает true, войдите в систему с соответствующей учетной записью.
Это стратегия, принятая Gatekeeper для долгосрочной аутентификации пользователей, и это наиболее безопасная стратегия, предложенная на сегодняшний день для удовлетворения этого требования.
Вы можете безопасно достичь того, чего хотите, используя AES в режиме EAX. Зашифрованный текст будет больше, чем открытый текст; это нормально для безопасного шифрования.
Злоумышленник, конечно, будет знать длину вашего открытого текста из зашифрованного текста, но он не сможет определить что-либо еще.
Генерация ключей AES случайным образом.
Убедитесь, что для каждого шифрования используется новый одноразовый номер, и используйте поле "связанные данные", чтобы гарантировать, что то, что вы зашифровали для одной цели, не будет представлено как предназначенное для другой (поэтому такие вещи, как имя пользователя и имя файла cookie, могут войти в там)
Реакция ниже подталкивает к: Не доверяйте шифрованию для обеспечения безопасности.
Подробнее "если вы не специалист по шифрованию, вы недооцените, насколько легко ошибиться". Например, AFAICT, никто другой в этой теме не обсуждал режимы цепочки или целостность сообщений, которые охватывают две распространенные ошибки новичка.
Как отмечалось несколько раз в предыдущих комментариях, вы должны применять защиту целостности к любому зашифрованному тексту, который вы отправляете пользователю и принимаете обратно. В противном случае защищенные данные можно изменить или восстановить ключ шифрования.
Особенно мир PHP полон плохих примеров, которые игнорируют это (см. Криптография PHP - действуйте осторожно), но это применимо к любому языку.
Одним из немногих хороших примеров, которые я видел, является PHP-CryptLib, который использует комбинированный режим шифрования-аутентификации для выполнения этой работы. Для Python pyOCB предлагает аналогичную функциональность.
Хотя оба очень сильные, AES является стандартом.
Что касается безопасности небольших порций данных: чем меньше, тем лучше. Чем меньше данных зашифровано, тем дольше вы можете использовать ключ. Всегда существует теоретический предел того, сколько данных может быть зашифровано в одном ключе данного алгоритма, не подвергая систему риску.
Если вы зашифровываете cookie, серверу все равно придется декодировать его, чтобы прочитать его (для проверки того же ключа), поэтому любой зашифрованный cookie не имеет смысла, потому что если его украсть (и не отредактировать), он все равно приведет хакера прямо к вашей учетной записи., Это так же небезопасно, как и вообще не зашифровано.
Я полагаю, что реальная проблема того, что кто-то украл ваш cookie, - это связь между сервером и клиентом. Используйте SSL-соединение, предоставленное вашим хостом.
Что касается вашего cookie, вам нужно сделать длинный случайный идентификатор для каждого пользователя в базе данных (он должен меняться при каждом входе в систему) и просто установить его как cookie или сеанс. Файл cookie, содержащий ключ, может быть проверен с помощью php, и, если он равен учетной записи или таблице в вашей базе данных, выведите данные на веб-страницу, как обычно.
Почему вы хотите зашифровать куки?
На мой взгляд, есть два случая: либо вы даете клиенту ключ, либо нет.
Если вы не даете ключ клиенту, то почему вы даете им данные? Если вы не играете в какую-то странную игру с нарушением слабого шифрования (чего явно нет), вы можете также хранить данные на сервере.
Если вы передаете клиенту ключ, то зачем вы его зашифруете? Если вы не шифруете передачу ключа, то шифрование cookie является спорным: MITM может посмотреть файл cookie и отправить вам любой файл cookie, который он хочет. Если вы используете зашифрованный канал для клиента, зачем тратить дополнительные деньги на шифрование хранимых данных?
Если вы беспокоитесь о том, что другие пользователи на клиентском компьютере читают куки, сдавайтесь и предполагайте, что браузер устанавливает хорошие биты разрешений:)
AES (также известный как Rijndael) является самым популярным. Размер блока составляет 128 бит, это всего 16 байтов, и вы говорите "около 100 символов".
Кроме того, я попробовал mcrypt_encrypt
и одну вещь, пожалуйста, имейте в виду. Если вы делаете base64_encode(mcrypt_encrypt(...))
,
а потом, вы делаете base64_decode
и вывести зашифрованные данные (echo
). Вы наверняка облажаетесь и ничего не видите. Тем не менее, если вы делаете mcrypt_decrypt( ... base64_decode($value) )
, Вы увидите исходные данные.
Я думаю, что "отдавать" любые данные, даже зашифрованные, когда речь идет об имени пользователя и пароле, нехорошо... Есть много JS, которые могут их прослушать... Я предлагаю вам создать в таблице БД пользователей поле cookie_auth или что-то еще..,
после первого входа в систему собираются: текущий: браузер, IP, и какой-то собственный солт-ключ, плюс ваше имя хоста var...
создать хеш и сохранить в этом поле... установить cookie... когда cookie "отвечает", сравнить все это с сохраненным хешем и готово...
даже если кто-то "украдет" печенье, он не сможет его использовать:-)
Надеюсь это поможет:-)
feha vision.to
Было сказано так много ужасающих вещей, что, тем не менее, правда, но давайте посмотрим на светлую сторону: немного здравого смысла и постоянное наблюдение за вашим сайтом могут спасти вас все время.
Сохранение файлов cookie - важная часть веб-разработки, поэтому игнорировать его нельзя. Но также мы должны избегать как можно большего; Я вижу использование файлов cookie только в том случае, если я хочу продлить сеанс входа в систему даже после того, как пользователь закроет браузер. Если кто-то не хочет продлевать сеанс пользователя за пределы закрытия браузера, следует использовать компонент Session. Даже при использовании компонента сеанса следует помнить о захвате сеанса.
В любом случае, вернемся к Cookie; На мой взгляд, если следовать приведенным ниже мерам предосторожности, я почти уверен, что мы будем в большей безопасности.
Я делю precautionary measurement
в двух фазах
Фаза 1: Разработка
- Установлен
path
атрибут - Установлен
expiration_date
- установлен
secure
,httpOnly
атрибуты - Используйте новейшие алгоритмы шифрования
- Используйте два алгоритма: например, используйте
blowfish
а затем используйтеbase64_encode
Сверху.
Этап 2: Эксплуатация / Аудит
- Периодически проводите аудит сайта, используя такие инструменты, как
burp
.