Цифровые подписи - HOWTO

anight

Новичок
Цифровые подписи - HOWTO

DiMA wrote:
> Ну что, поговорили и забыли? Некий товарищ с высоты своих знаний
> заявил, что тут изобретен велосипед (хотя изобретать то и нечего - все
> очевидно из свойств функции md5) и более ничего не уточнил.

я рад, что мою высоту знаний оценил аж DiMA :)
как и обещал - уточняю.

maxim wrote:
> а если кратко, то в чем суть цифровых подписей? как их использовать?

ээ.. попробую на простом примере:

допустим есть сервер, на нем n зарегистрированных пользователей
каждый пользователь может менять информацию о себе и только о себе.
форма, через которую это делается должна содержать два hidden поля - логин и пароль этого пользователя.
после отсылки формы сервер проверяет логин и пароль - СВЕРЯЕТСЯ С БАЗОЙ ДАННЫХ (важно!) - и если все ок - записывает изменения.
в данном примере пароль является необходимым, т.к. подтверждает что
пользователь тот, за кого он себя выдает.

а теперь пример этой же задачи, но с применением цифровых подписей.
форма содержит 2 hidden поля: логин и цифровую подпись этого логина - пароль вообще не нужен :)
для генерации цифровой подписи сервер может использовать примерно такую
формулу:
$sign = md5($login . "SoMeSuPeRdIfFiCuLtPaSsWoRd");
а проверять ее так:
if (md5($login_from_form . "SoMeSuPeRdIfFiCuLtPaSsWoRd") != $sign_from_form)
{ /* auth failed */ }
else
{ /* go on */ }

с одной стороны разницы никакой, но в случае авторизации с цифровой подписью
серверу не нужно лазить в базу чтобы проверить
есть ли там такой логин и пароль. и это принципиальное отличие.
сервер МОЖЕТ АВТОРИЗОВАТЬ КЛИЕНТА исходя исключительно из данных формы!
т.е. сервер "подписал" логин пользователя. и пользователь в принципе не
может подделать эту подпись, разве что перебором 128 - битной md5.

для авторизации, обсуждавшийся тут
http://phptalk.unet.ru/p/read.php?f=1&i=21007&t=21007
(собственно, с чего разговор и начался)
подошел бы следующий алгоритм:

1) сервер генерирует случайное 128 битное число $random и отсылает его
клиенту.
2) клиент на javascript получает $client_md5 = md5($client_password .
$random)
3) сервер проверяет его:
if (md5($server_password . $random) == $client_md5)
{ /* go on */ }
else
{ /* auth failed */ }

эта схема не оставляет надежд тому, кто будет пытаться совершить атаку путем
перехвата http трафика.
однако для пущей безопасности можно добавить то, что предложил DiMA: а
именно добавлять в аргумент md5 кроме random - время.

[... to be continued ...]
 

anight

Новичок
предвижу критику и объясняюсь:
цифровая подпись в криптографии это немного другое, и я взял на себя смелость называть вышеописанное цифровой подписью лишь потому что сохранено ее главное свойство, а именно: уникальность и то, что ее нельзя подделать.
кстати, применимо к web, можно к аргументу md5 прибавлять $REMOTE_ADDR:

$sign = md5($login . $REMOTE_ADDR . "сложный пароль");

пример приведенный в предыдущем посте примитивен, однако ухватив лишь идею ее можно развить и склепать кое-что посложнее.
все зависит от вашей фантазии :)
 

Jazzer

Guest
позвольте, так в случае с REMOTE_ADDR и придумывать-то больше ничего не нужно: md5($login.$REMOTE_ADDR) и всё! получается уникальный идентификатор клиента на момент его работы с нашим сервером... гениально, anight!
 

anight

Новичок
нет, в таком случае клиенту будет очень просто подделать подпись!
 

anight

Новичок
кстати, схему со тайм-аутом ключа, которую предложил DiMA можно упростить и усовершенствовать:
можно клиенту выдать время, когда авторизация устареет и подписать его!

например:

$hashkey1 = "very secret key";
$hashkey2 = "another secret key";
$auth_expired = time() + 5 * 60; // авторизация возможна не позже чем через 5 минут
$sign = md5($login . $hashkey1 . $auth_expired . $hashkey2 . $REMOTE_ADDR);

выводим клиенту в форму три hidden поля:
$login, $auth_expired и $sign.

после того, как отправил нам форму - проверяем:

$hashkey1 = "very secret key";
$hashkey2 = "another secret key";
if (md5($client_login . $hashkey1 . $client_auth_expired . $hashkey2 . $REMOTE_ADDR) != $client_sign)
{ // клиент подделал одно из трех полей!
die("Access denied!");
}
if (time() > $client_auth_expired) // ведь мы проверили что клиент ничего не подменял - значит этому времени можно доверять!
{
die("Your authentication is expired!");
}

Обратите внимание В КАКОМ ПОРЯДКЕ расположены аргументы md5 :
если бы поля, которые мы доверяем клиенту были расположены РЯДОМ, то у него появится дополнительная лазейка:

допустим, аргументы md5 были бы расположены так: $login, $auth_expired ...
тогда если у клиента login == "1234" и auth_expired == "938603554"
то подменив login на "123" и auth_expired на "4938603554" он получит неустареваемую авторизацию на чужой login!!!
(ведь простой конкатенацией строк мы получаем точно такой же аргумент для md5)

Это один из подводных камней, и с этим следует быть внимательней.
 

Jazzer

Guest
вот, придумал способ авторизации пользователя при вводе данных (логин и пароль) в форму - оцените на прочность:

на экран выдается форма с полями логин/пароль и полем "securitydate" типа hidden и значения = time(), а тем временем php генерирует уникальный ключ (к примеру, любое число от 1 до 10000), который записывается в базу, вместе с этим самым securitydate, который и служит указателем, что именно этому юзеру соответствует этот ключ.

после сабмита посредством md5 делаем вот что:

calcvalue = this.password.value + 'любое статическое слово' + '<?php echo $наш_ключ; ?>';
hash = calcMD5(calcvalue);
this.password.value = '';

("любое статическое слово" - чтобы не попасть в тот подводный камень, что упомянул anight)

далее передаем этот hash скрипту-обработчику, в котором по полю securitydate вылавливаем из базы ключ и из таблицы юзеров пароль, соответствующий нашему логину, и проверяем:

md5value = md5($пароль_из_базы."любое статическое слово".$наш_ключ);
if(md5value != hash) { echo "пошел на хер!" exit(); }


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


PS: да, базу с ключами иногда надо будет подчищать, т.к. не все пользователи, что доходят до страницы с формой, пытаются залогиниться. тут можно добавить в БД еще одно поле - timestamp - и по крону привесить скрипт, который будет раз в сутки удалять ключи, timestamp которых "протух".

PPS: остается вопрос, как реализовать подобные механизмы для регистрации пользователей (впервые), дабы в базу записать не хэш от md5, а настоящий пароль???
 
Сверху