Методы и алгоритмы шифрования информации на PHP

Статья уже старовата. Писал я её специально для 4-го выпуска журнала Mazafaka E-zine в сентябре 2005 года, если не ошибаюсь. Но, не смотря на это, решил её разместить и здесь :) .

В стандартной установке PHP предоставляет нам некотрые функции для шифрования, например, crypt() и md5(). Остальные нужно явно указывать при компиляции (mcrypt, mhash, cURL).

Функция crypt() выполняет односторонее DES-шифрование. Ей нужно передать обычный текст для шифрования, чтобы получить зашифрованный:

<?php
print crypt («text», «parametr»);
?>

Если второй параметр не указать, то PHP автоматически сгенерирует случайную пару символов для базиса шифрования. При помощи crypt() можно шифровать и по алгоритму md5 ( не только при помощи функции md5() ). Достаточно установить константу CRYPT_MD5 в 1.

Зададим базис, начинающийся с $1$ для использования md5 в функции crypt():

<?php
print crypt («text», «$1$parametr»);
?>

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

<?php
$key = «My cool key»; // просто текст
$data = «My secret data»; // инфа для шифрования
$alg = MCRYPT_BLOWFISH;
$mode = MCRYPT_MODE_CBC;
$iv = mcrypt_create_iv (mcrypt_get_iv_size ($alg, $mode), MCRYPT_DEV_URANDOM);
$encrypted_data = mcrypt_encrypt ($alg, $key, $data, $mode, $iv);
$plain_text = base64_encode ($encrypted_data);
print $plain_text.»\n»;
$decoded = mcrypt_decrypt ($alg, $key, base64_decode($plain_text), $mode, $iv);
print $decoded.»\n»;
?>

Почти ничего не понятно, да :) ? Сейчас постараюсь объяснить. Все данные шифруются и расшифроввываются с помощью функций mcrypt_encrypt() и mcrypt_decrypt(). Каждая их них принимает пять аргументов.

Первый аргумент – применяемый алгоритм. Все поддерживаемые алгоритмы можно посмотреть, вызвав функцию mcrypt_list_algorithms(). Второй аргумент – это ключ шифрования, третий – данные, которые шужно зашифровать и наоборот.
Четвертый аргумент устанавливает режим шифрование или расшифровки.
Пятый аргумент – вектор инициализации (IV), он используется режимами в качестве составляющей. Первый аргумент функции mcrypt_create_iv() – это длина вектора, второй – источник случайности (в данном случае – /dev/urandom).

Можно применять MCRYPT_DEV_RANDOM и MCRYPT_RAND. Но тогда надо вызывать функцию srand(), т.к. не все ОС поддерживают псевдоустройства случайных генераторов (это касается функции MCRYPT_RAND).

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

Сколько раз уже было сказано, что не нужно хранить пароли в открытом виде на своих сайтах и директориях, доступных через веб, а большинство почему-то продолжают делать именно так =)!

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

mysql_connect (‘localhost’, $_ENV['MYSQL_USER'],
$_ENV['MYSQL_PASSWORD']);

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

SetEnv MYSQL_USER «user»
SetEnv MYSQL_PASSWORD «your_pass»

Этот файл нужно включить в директиву <VirtualHost> в главном конфигурационном файле:

Include «/path_to_file/»

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

<?php
$word = ’some_word’;
$id = 100;
$hash = md5 ($word . $id);
print<<<_HTML_
<input type=»hidden» name=»id» value=»$id»>
<input type=»hidden» name=»idhash» value=»$hash»>
_HTML_;
?>

После получения обратно проверяем:

<?php
$word = «some_word»;
if (md5($word . $_REQUEST['id']) == $_REQUEST['idhash']) {
$id = $_REQUEST['id'];
} else {
die («Invalid data»);
}
?>

Для использования хеша в cookie изменим немного этот скрипт:

[skip]
….
$cookie_value = ‘m0zg’;
$hash = md5 ($word . $id);
setcookie (‘name’, join(‘ | ‘, array($cookie_value, $hash)));

Проверяем полученное:

<?php
$word = ’some_word’;
list ($cookie_value, $cookie_hash) = explode (‘ | ‘, $_COOKIE['name'], 2);
if (md5($word . $cookie_value) == $cookie_hash) {
$name = $cookie_value;
} else {
die («Invalid data»);
}
?>

Конечно, если кто-то узнает это секретное слово, то вся работа впустую. Тут можно либо менять его постоянно, либо пользоваться переменной $id, т.е. несколько разных слов, выбранных с помощью $id%10 (если 10 слов). Можно использовать модуль mhash, тут вы не будите ограничены хешами в md5. Он поддерживает несколько алгоритмов
хеширования.

А теперь хотелось бы затронуть тему шифрования почты. Использовать будем GPG (ибо Open Source!). Сначала код, а потом пояснения.

<?php
$message = escapeshellarg($message);
$gpg_path = ‘/usr/local/bin/gpg’;
$sender = ‘user@mailserver.com’;
$rcpt = ‘to@someserver.com’;
$home = ‘/home/user’;
$user_env = ‘user’;
$cmd = «echo $msg | HOME=$home USER=$user_env $gpg_path » . ‘–quit–no-secmem-warning –encrypt –sing –armor’ . » –recipient $rcpt –local-user $sender»;
$message = ‘$cmd’; mail($rcpt, ‘GPG Mailer’, $message);
?>

С начала мы вызываем программу GPG, расположенную в
/usr/local/bin/gpg для шифрования сообщения из $message. Она использует закрытый ключ, который принадлежит Вам ($sender), и открытый ключ, принадлежащий $rcpt. Теперь только он сможет расшифровать Ваше сообщение.

Установка переменных окружение HOME и USER указывает GPG, где ей нужно искать свои настройки шифрования ($HOME/.gnupg/secring.gpg).
Параметры –quiet и –no-secmem-warning подавляют предупреждения GPG, которые в противном случае были бы сгенерированы и добавились к тесту сообщения.

Параметры –encrypt и –sing заставляют GPG зашифровать
сообщение и подписать его. Шифрование сообщение закрывает его от любого, кроме адресата. В подписи содержится информация о том, кто составил сообщение и когда.

Параметр –armor генерирует простой текст вместо двоичного кода, для более удобной рассылки.

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

Очень много можно написать по этой теме, но статью сильно растягивать не хочется =).

Ссылки по теме:

http://www.php.net/md5
http://www.php.net/mhash
http://www.php.net/crypt
http://www.php.net/mcrypt

6 comments so far

  1. Саша on

    Давайте больше информации по данной тематике!

  2. Ласточка on

    Спасибо за прекрасную статью. Желаю побольше подобного материала.

  3. al-Ma'din on

    Товарищ курсант! Вы уподобляетесь африканской птице страусу, которая с высоты своего полета не видит генеральной линии партии.

  4. gajets on

    Чем дальше – тем итренеснее. Желаю удачи в развитии!)

  5. petya on

    Ну, как сказать, понравилось :) Хотя я все равно практически ничего не понял. :)

  6. ZEXEL on

    А какие еще есть системы шифрования кроме етих четырех ?
    Как зашифровать методом md4 ?


Ответить