При необратимом шифровании информация зашифровывается таким образом, что не подлежит обратной расшифровке. На первый взгляд это может показаться странным, но в действительности такой метод шифрования используется очень часто. Функция, с помощью которых реализуется однонаправленное шифрование, называются функциями хэширования. При использовании таких функций создается уникальный "отпечаток" строки. Наиболее часто в качестве алгоритма хэширования используется алгоритм MD5, реализовать который можно с помощью одноименной функции:
string md5($str [, $raw_output])
В качестве обязательного аргумента функция принимает строку $str, которую необходимо зашифровать и возвращает ее уникальный 128-битовый отпечаток (хэш-код). Если необязательный аргумент $raw_output имеет значение true, то возвращается бинарная строка из 16 символов. Вероятность того, что две строки дадут одинаковый хэш-код, стремиться к нулю.
Примечание. Аналогичная функция md5_file() часто используется для создания уникального хэш-кода объемных файлов, которые передаются по сети. Загрузив файл, всегда можно проверит его целостность, вычислив код по алгоритму md5 и сравнив полученный результат с хэш-кодом, представленным распространителем. Это позволяет отследить повреждения файла, вызванные передачей через сеть, а также предотвращает фальсификацию файла. Такой способ часто применяют при распространении объемных дистрибутивов.
При помощи этой функции можно зашифровать различные данные, к примеру, пароли пользователей. Это позволит организовать следующий алгоритм авторизации пользователей. При первой регистрации пользователя сохраняется хэш-код его пароля (например, в базе данных). При последующих посещениях странички хэш-код вводимого пользователем пароля сравнивается с сохраненным ранее хэш-кодом. Если отпечатки совпадают авторизация считается успешной.
Примечание. Такая схема авторизации не позволяет получить непосредственный доступ к паролям, даже если происходит хищение базы данных. В этом случае злоумышленник вынужден тратить значительное машинное время на перебор паролей по словарю, поэтому пароли вида W3t6,8yt6P практически не поддаются расшифровке, в тоже время необратимое шифрование не сможет защитить от перебора при пароле вида 12345.
При помощи функции md5() можно зашифровать различные данные, к примеру пароли пользователя.
Использование функции md5()
<?php
$maks_password="dghbcdj27hg"; //Сохраненный пароль пользователя
$maks_cipher=md5($maks_password); //Сохраненный хэш-код пароля
//Пароль пользователя вводимй при посещении странички
$user_password="dghbcdj27hg";
//Хэш-код пароля пользователя, вычисляемый при посещении странички
$user_cipher=md5($maks_password);
//Если хэш-коды совпадают то пароль верный
if($maks_cipher==$user_cipher)
{
echo "Hello, Maks";
}
else
{
echo "Введен не верный пароль";
}
?>
Для этих же целей используется функция crypt(), которая имеет следующий синтаксис:
string crypt($str [, $salt])
Аргумент $strпредставляет собой предназначенную для шифрования строку. К примеру, если передавать этой функции строку с паролем "dghbcdj27hg" и аргумент $salt, равный "ttt", то будет возвращена строка "ttqHdgPBP2/UI", которая не может быть дешифрована. Однако, поскольку результат работы функции строго определен в том смысле, что при вызове с одинаковыми параметрами $str и $salt функция возвращает один и тот же результат, ее можно использовать для проверки паролей.
Примечание. В UNIX-подобных ситемах и Windows хэш-код, возвращаемый функцией crypt(), не совпадает. В UNIX-подобной операционной системе результат функции crypt() можно использовать для автоматического выполнения файла .htpasswd, используемого совместно с конфигурационным файлом .htaccess для защиты директории паролем.
Использование функции crypt()
<?php
$maks_password="dghbcdj27hg";
$maks_crypt=crypt($maks_password, 'ttt');
echo $maks_crypt;
$user_password="dghbcdj27hg";
$user_crypt=crypt($maks_password, 'ttt');
if($maks_crypt==$user_crypt)
{
echo "<br>Пароли совпадают ";
}
else
{
echo "Введен неверный пароль";
}
?>
В окне веб-браузера это будет выглядеть ТАК.
Для однонаправленного шифрования можно также использовать функцию crc(), вычисляющую 32-битовую контрольную сумму исходной строки:
int crc($str)
Для работы с паролями эта функция, как правило не применяется, поскольку создает лишь 32-битовый хэш-код. Обычно этой функцией пользуются для проверки совпадения данных . С помощью этой функции, к примеру, удобно проверять, был ли изменен файл со времени последнего просмотра, совпадаютли перемещенные данные и т.д.
При симметричном шифровнии строки шифруются с помощью ключа, который известен как отправителю так и получателю. В РНР алгоритмы симметричного шифрования реализованы в библиотеке mcrypt; ознакомиться с полным набором функций и алгоритмов этой библиотеки можно на сайте http://www.php.net. Функции mcrypt работают, только если подключена библиотека mcrypt.
Примечание. Как и любое расширение, по умолчанию библиотека mcrypt в РНР5 отключена. Для того, чтобы ее подключить, необходимо убрать комментарий напротив строки extension=php_mcrypt.dll в конфигурационном файле php.ini. Кроме того, необходимо скопировать в системную директорию C:/Windows/system32 библиотеку libmcrypt.dll из дистрибутива РНР. Если данная библиотека не входит в состав дистрибутива РНР, то ее следует загрузить из сети, например по ссылке http://www.softtime.ru/libmcrypt.dll.
Рассмотрим пример, в котором строка зашифровывается и расшифровывается при помощи алгоритма 3DES(Triple-DES).
Использование симметричного шифрования
<?php
//Шифруем пароль
$user_password="dghbcdj27hg";
$key="Это секретный код";
//Шифруем пароль с использованием секретного ключа $key
$user_crypt=mcrypt_ecb(MCRYPT_3DES, $key, $user_password, MCRYPT_ENCRYPT);
echo "Зашифрованный пароль - $user_crypt <br>";
//Расшифровываем пароль
$user_crypt=mcrypt_ecb(MCRYPT_3DES, $key, $user_crypt, MCRYPT_DECRYPT);
echo "Расшифрованный пароль -$user_crypt";
?>
В окне веб-браузера это будет выглядеть ТАК.
В данном примере, пароль, размещенный в переменной $user_password, сначала шифруется функцией mcrypt_ecb() с применением ключа $key, а затем проводится его обратная дешифрация.
Как видно из рассмотренных примеров, для шифрованию паролей зачастую проще прибегать к необратимому шифрованию. Однако это не значит, что пароль, особенно простой, невозможно подобрать. Рассмотрим простейший скрипт подбора пароля методом перебора символов из массива $arr. При этом пароли располагаются в файле password, расположенном в той же директории,что и скрипт. Переменная max_number задает максимальный размер подыскиваемого пароля.
Примечание. Обычно подбор осуществляется не для каждого отдельного пароля, а для целой совокупности — ведь для каждого пароля перебираются одни и те же значения, следовательно можно экономить время, если обрабатывать все четыре пароля из файла password за один раз. Кроме того, реальный инструмент зачастую реализуют на компилируемом, а не интерпретируемом языке программирования.
Подбор пароля, зашифрованного с помощью MD5
<?php
//Устанавливаем неограниченное время выполнения скрипта
set_time_limit(0);
//Читаем пароли из файла password
$pass=file("password");
foreach($pass as $password)
{
//Замеряем время, затраченное на подбор пароля
$begin=time();
echo decrypt_md5(trim($password),"");
$end=time();
echo "(На подбор затрачено ".($end-$begin)."секунд)<br>";
}
//Функция символического подбора пароля
//$pass-расшифрованный пароль
// $answer- текущий ответ, при первом вызове - пустая строка
function decrypt_md5($pass, $answer)
{
$arr=array('a','b','c','d','e','f',
'g','h','i','j','k','l','m','n','o','p',
'q','r','s','t','u','v','w','x','y','z');
//Будем считать, что пароль не превышает
//4 символов
$max_number=3;
if(strlen($answer)>$max_number) return;
for($j=0; $j<count($arr); $j++)
{
$temp=$answer.$arr[$j];
if(md5($temp)==$pass)return $temp;
//Рекурсивно вызываем функцию для увеличения
//длины подбираемого пароля
$result=decrypt_md5($pass, $temp);
//Если функция возвращает не пустую строку,
//следовательно, найден ответ и дальше искать не следует
if(strlen($result)>0) return $result;
}
}
?>
Время выполнения скрипта может быть значительным, поэтому в первых строках снимается ограничение на время выполнения скрипта при помощи функции set_time_limit(). Функция принимает единственный целочисленный параметр, через который передается новое значение максимального времени выполнения скрипта. Если в качестве параметра передано значение 0, любые ограничения на время выполнения снимаются.
После этого содержимое файла password разбиваются на строки, помещаемые в массив $pass, элементы которого в цикле передаются рекурсивной функции decrypt_md5().
Примечание. Следует отметить, что строки массива $pass пропускаются через функцию trim(), для того чтобы избавиться от невидимых символов \r\n, которые могут оставаться в конце строк.
Функция перебирает значения от а через ab, ac и до azzz, и как только временная переменная $аanswer принимает значение аааа, функция переходит к символу b и перебирает пароли до bzzz. Таким образом перебираются все символы из массива $arr. Как только пароль найден, функция возвращает его и выходит из рекурсивного цикла благодаря проверке:
if(strlen($result)>0) return $result;
Зачастую пароль подбирается гораздо быстрее, если поиск осуществляется по словарю, т.е. не перебором всех возможных значений, а путем выбора из словаря наиболее употребляемых слов.
Для генерации паролей воспользуемся случайной выборкой из массива элементов. Можно управлять частотой появления символов в пароле, добавлением дублирубщих элементов в массиве. Например, часто в массив -источник добавляются дублирующие буквы верхнего регистра. Следует подавлять такие желания, т.к. изменение частоты символов в пароле играет на руку злоумышленникам, которые, зная особенности генерации паролей, могут значительно сократить время подбора.
Генератор паролей
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=windows-1251">
<title>Генератор паролей</title>
</head>
<body>
<form action="" method="post">
<input name="number" type="text" value="8" size="25">
<input name="" type="submit" value="Генерировать">
</form>
<?php
//Параметр $number указывае количество символов в пароле
echo htmlspecialchars(generate_password($_POST['number']));
function generate_password($number)
{
$arr=array('a','b','c','d','e','f',
'g','h','i','j','k','l','m','n','o','p',
'q','r','s','t','u','v','w','x','y','z',
'A','B','C','D','E','F','G','H','I','J',
'K','L','M','N','O','P','Q','R','S','T',
'U','V','W','X','Y','Z', '1','2','3','4',
'5','6','7','8','9','0', ',','.','(',')',
'[',']','!','?','$','^','%','@','*','$',
'<','>','/','|','+','-','{','}','~','`');
//Генерируем пароль
$pass=" ";
for($i=0; $i<$number; $i++)
{
//Вычисляем случайный индекс массива
$index=rand(0, count($arr)-1);
$pass.=$arr[$index];
}
return $pass;
}
?>
</body>
</html>
В окне веб-браузера это будет выглядеть ТАК.