+1 к защите пароля методом тройного хеширования. Бред?
Возникла достаточно дикая идея: реализовать безопасность передачи пароля по нешифрованному каналу связи во время авторизации и защитить пароль от вскрытия, имея базу данных и алгоритмы приложения. Не судите строго, способ придуман за 5 минут в 4 часа ночи (или утра) и претендует только на звание «легкогой» защиты (для форумов и прочих сайтов, не требовательных к безопасности).
Регистрация:
Человек генерирует md5 пароля (не передавая сам пароль, в чем нет нужды), отправляет на сервер, где высчитывается еще одна сумма (md5(hash)) === md5(md5(password)) и добавляется в поле hash_of_hash таблицы с юзерами. Операция небезопасна, так как хеш может быть перехвачен и использован для авторизации (хеш пароля, образно выражаясь, сам стал паролем), поэтому требуется удача или безопасный канал связи. Этот ход нужен, как было указано выше, только для невозможности получения исходного пароля после хищения злоуышленником базы (известно, что многие используют один и тот же пароль и для вконтактика и для интернет-банка, например).
Авторизация:
1. Клиент (в данном случае браузер) запрашивает рандомый ключ (например, 1234) по открытому каналу связи.
2. Отправляет на сервер md5(md5(md5(password))+1234) = «qwer», сгенерированный JS кодом
3. Сервер делает запрос к базе:
(SQL-подобный псевдокод)
SELECT user FROM users WHERE md5(hash_of_hash+1234) = «qwer»
И авторизует соответствующего юзера. Рандомный ключ уникален для каждого запроса этого ключа. Трафик всё еще можно подслушать, но, вот, «войти» будет гораздо сложнее (по крайней мере, юзер будет знать, если его данные перехватил «человек по середине»).
Совсем идиотизм? Или способ имеет право на жизнь (хотя бы часть с авторизацией, используя двойное хеширование против тройного).
Кстати, у меня была такая-же идея, только без тройного хеширования - просто запрашиваешь рандомное число и зашифровываешь его паролем, отправляешь, сервер расшифровывает число с помощью твоего пароля из базы данных и если расшифрованное число равно изначальному - ты авторизован. У меня это было для связи сервер-сервер.
Нет никакой разницы, что использовать в качестве первичной информации — пароль, его хеш, его сумму с какой-то известной строкой или любое другое однозначное преобразование.
Криптостойкость системы от этого ни возрастает, ни падает.
Дык это, если злоумышленник уведет базу hash_of_hash, как вы ее называете, то он сможет спокойно авторизовываться в качестве любого пользователя в дальнейшем, разве нет? Например, Ева знает hash_of_hash Алисы. Ева запрашивает ключ. Получает 1234. Вычисляет md5(hash_of_hash+1234) отправляет все дело серваку. Тот вычисляет md5(hash_of_hash+1234) и Ева внутри. Получается что в базе у вас будут лежать данные, используя которые злоумышленник может успешно авторизоваться. А это не есть хорошо.:)
Хэш как пароль приведет к конечному количеству комбинаций. 30^32 — не так уж мало, но пароль вида "C6+~Z4tx==n порой может быть даже помощнее чем полученный от него хэш.
Затем, переводя все пароли в md5(pass) вы делаете так, что некоторых разных паролей md5 совпадает (из-за коллизий), что тоже не хорошо. А делая md5(md5(md5(x))) — вы только увеличиваете коллизии, также как sin(sin(sin(x))) только упростит график sin. Соответственно только вредит.
Ну, если подумать имея рандомный ключ и имея хэш с этим ключем особо ничего не сделать. Это только если этот ключ будет меняться. По сути вытащить пароль не выйдет и исполовать хэш тоже не выйдет. Но только учтите что делать придется так, юзер вводит пароль он хэшируется, потом вместе с ключем. то есть
md5(md5(password)+1234) (синтаксис схожий с js)
Все это дело отправляется на сервак, там мы имеем захэшированный пароль и ключ (храним в сессии например) и делать надо что то вроде
SELECT id FROM users WHERE md5(phw.'.$key.') = '.$phw.' limit 1;
тогда в общем то все безопасно при перехвате.
Можно ещё по-другому поступить. Выбрать один из криптоалгоритмов, в которых шифрование можно производить открытым ключём, а дешифрование — закрытым. Передавать брузеру открытый ключ, принимать зашифрованный пароль, и дешифровать его на серверной стороне закрытым ключём.
В этом случае, перехват открытого ключа ничего злоумышленнику не даст, т.к. им можно только зашифровать, но не расшифровать.
Перехват зашифрованного пароля тоже ничего не даст, т.к. закрытый ключ есть только у сервера.
Ну, и хранить пароли в БД классически: hash + salt.
P.S. А не проще ли на страничке авторизации ввести https?
Посмотрите как сделали в Stripe — они используют асимметричное шифрование и передают данные кредитки в виде токена.
Уже есть jQuery плагин jCryption, который работает по такой схеме (цитата с сайта):
1) Client chooses a Password … (in the example a weak one, you should use a good random number in production e.g. mousemovement coordinates)
2) Client requests RSA Public key from Server
3) Client encrypts Password with RSA Public key
4) Server decrypts Password and stores it in the session
5) Server Encrypts the Password with AES and sends it back to the Client
6) Client decrypts it with AES with the Password
7) Both have now the same “secret” key which is used for communication
1. Боб запрашивает у Алисы key и keyid.
2. Алиса генерирует случайное число key и записывает в свою базу данных такие значения:
"key"=key, "keyid"=keyid, "expires"=(текущая дата плюс 2 минуты).
3. Алиса отправляет Бобу key и keyid (у Сэма появились key и keyid).
4. Боб отправляет Алисе такие данные:
"login"=login, "encripted_pass"=md5(key||pass||key), "keyid"=keyid (у Сэма появились login, encripted_pass).
5. Алиса достает expires, соответствующий keyid из своей базы данных. Если expires меньше текущей даты, Алиса отправляет Бобу ошибку "Timed out". Иначе, выполняются следующие шаги.
6. Алиса достает pass, соответствующий login и key, соответствующий keyid из своей базы данных. Вычисляет md5(key||pass||key) и сравнивает с encripted_pass. Если вычисления совпали, авторизация пройдена.
7. Алиса, независимо от того, успешна ли авторизация, записывает в строку expires, соответствующую значению keyid, значение "false".
У Сэма есть значения key, keyid, login, encrypted_pass.
Он не может повторно использовать encrypted_pass, так как "expires"="false" в поле, соответствующем keyid в базе данных Алисы.