Видимо, хэширование имени пользователя и пароля и сохранение их в виде файлов cookie и вход в систему с данными для очистки файлов cookie недостаточно для вас людей (или безопасности моего сайта).
Этот подход достаточно хорош?
Процедура регистрации:
$salt= date('U'); $username= hash('sha256', $salt. $_POST['username']); $password= hash('sha256', $salt. $_POST['password']); $token = hash('sha256', $salt. (rand(1,10000000000000000000000000000000000000000000)));
Для входа в систему вручную пользователи вводят свое имя пользователя и пароль, они передаются через хэш и сопоставляются.
После успешного входа в систему для пользователя создаются два кулинарных файла. Один из них содержит неподтвержденное имя пользователя, а другой – хешированный токен.
Когда пользователь посещает, если файлы cookie установлены, сайт хэширует имя пользователя, а затем использует эти два значения для входа.
Преимущество такого подхода заключается в том, что он позволяет избежать сохранения пароля пользователя в любом месте на своем компьютере. Кто-то может взломать токен и получить доступ к своей учетной записи, но, по крайней мере, я бы не поставил под угрозу пароль пользователя …
Люди, которые ответили на строку MySQL real_escape
и куки, говорят, что хранить данные пользователя в real_escape
cookie не так. Это отвлекает проблему?
Почему вам нужно хранить пароль вообще, даже зашифрованную версию? Является ли ваш сайт доступом к стороннему API в бэкэнд, который выполняет HTTP Basic auth или что-то еще?
К сожалению, окончательного ответа на ваш вопрос нет. «Подходящий» означает разные вещи для разных людей. И с вопросами безопасности, я не уверен, что когда-либо возможно быть «достаточно подходящим» или «достаточно безопасным». Тем не менее, вот как я обрабатываю логины и безопасность паролей. В таблице users
моей базы данных у меня есть 3 столбца, связанные с регистрацией:
Столбец username
имеет простой текст. salt
столбец представляет собой 64-символьную строку случайно выбранных буквенно-цифровых символов. Столбец passwordHash
– это пароль пользователя, связанный со значением salt
, а затем необратимо хэшированный. Я использую sha256 для своих хешей. Соль составляет 64 символа, потому что это то, что производит sha256. Хорошо иметь значение соли, по крайней мере, до тех пор, пока хеш для получения достаточной изменчивости в хешированной строке.
Когда пользователь отправляет форму входа, я делаю запрос базы данных для имени пользователя. Если имя пользователя не найдено, я показываю пользователю ошибку «Недопустимое имя пользователя и / или пароль». Если имя пользователя найдено, я конкатенирую соль с паролем, хеширую его и проверяем, равно ли оно значение passwordHash
. Если нет, пользователю будет показана точно такая же ошибка.
Хорошо показывать то же сообщение об ошибке независимо от того, было ли имя пользователя неправильным, или пароль был неправильным, или и то, и другое. Чем меньше подсказок вы дадите хакеру, тем лучше. Кроме того, всякий раз, когда пользователь меняет свой пароль, я даю им и новую salt
. Это действительно легко сделать в этот момент времени, и это сохраняет солевые значения немного свежее.
Эта система с различной солью для каждого пользователя называется динамическим солечением . Это значительно усложняет работу хакера, если они пытаются использовать таблицы радуги, чтобы перепроектировать пароли ваших пользователей. Не говоря уже о том, что хранение паролей в необратимо хэшированной форме очень долгий путь к тому, чтобы кто-либо определял пароль пользователя, даже если у них есть доступ к базе данных и PHP-коду.
Это также означает, что если ваш пользователь забыл свой пароль, нет способа извлечь его. Вместо этого вы пишете свою систему, чтобы просто переустановить ее на новое случайно определенное значение, которое отправляется им вместе с сильным поощрением, чтобы сменить пароль, как только они войдут в систему снова. Вы можете даже написать свою систему, чтобы принудительно это сделать при следующем успешном входе в систему.
Мне требуется пароли не менее 8 символов. В идеале, он должен также включать числа и специальные символы, но я не решил, что должен это требовать. Возможно я должен!
Чтобы защитить от атак с использованием грубой силы , я отслеживаю все неудачные логины в течение предыдущих 10 минут. Я отслеживаю их по каждому IP-адресу. После 3 неудачных попыток входа в систему система использует функцию sleep()
чтобы отложить ответ на дальнейшие попытки входа в систему. Я использую блок кода следующим образом:
$delay = ($failedAttempts - 3); if ($delay > 0) { sleep($delay); }
IMHO это намного лучше, чем блокировать пользователей из своих учетных записей после жесткого числа сбоев. Это уменьшает количество запросов на поддержку клиентов, которые вы получите, и это более грациозно для законных пользователей, которые просто не могут запомнить свои собственные пароли. Атаки грубой силы должны делать много попыток в секунду, чтобы иметь какую-то эффективность, поэтому откладывание на основе n = x
позволяет им получить очень далеко.
Входные сеансы отслеживаются с помощью сеансов PHP. Вызовите session_start()
когда загружается каждая страница вашего сайта. (Это очень просто, если у вас есть общий файл header.php
.) Это делает доступной переменную $ _SESSION . Когда пользователь успешно войдет в систему, вы можете использовать его для хранения информации, необходимой вашему сайту, чтобы узнать, что пользователь вошел в систему. Обычно я использую их идентификатор пользователя, имя пользователя и, возможно, некоторые другие детали, специфичные для сайта. Но здесь я не указываю пароль или хэш. Если каким-то образом хакер попал в данные сеанса пользователя, которые хранятся на вашем сервере, у них все равно не будет возможности найти пароль пользователя таким образом.
Выход из системы происходит, когда происходит одна из двух вещей: либо 1) cookie сеанса пользователя удаляется, например, очищая кеш браузера, а иногда просто закрывая окно браузера, или 2) ваш сервер удаляет свои данные сеанса. Вы можете заставить последнее произойти, вызвав session_destroy()
когда пользователь нажмет кнопку «Выход» на вашем сайте. В противном случае вы можете заставить сеансы автоматически истекать через определенный промежуток времени. Это может включать в себя настройку параметров session.gc_*
params в php.ini
.
Если вы обязательно должны знать пароль пользователя после начальной фазы входа, вы можете сохранить его в $_SESSION
. Сделайте это ЕСЛИ И ТОЛЬКО ЕСЛИ ваш сайт требует SSL-соединения, и вы сделали это, чтобы сайт не работал без него. Таким образом, пароль зашифровывается и защищается от обнюхивания пакетов . Но знайте, что это риск безопасности, если хакер получает доступ к данным сеанса вашего сервера.
Ваша соль не достаточно случайна.
Проблема с этим – атака повтора. Предположим, что плохой парень собирает файлы cookie пользователя на пути к вашему сайту. Что мешает ему (плохим парнем) отдать одни и те же ценности и войти, как если бы они были подлинным пользователем?
Плохо хранить пользовательские данные в файлах cookie. То, что вам может уйти, – это сохранить в браузере пользователя одно случайное 64-разрядное число. В базе данных аутентификации вашего приложения вы записываете случайные числа и основные свойства, такие как имя пользователя, время, когда файл cookie был первым действительным, когда он истекает, и, возможно, информация о браузере и информация о IP-адресе.
Когда cookie отправляется, вы подтверждаете, что он, похоже, поступает из того же браузера, что и при отправке файла cookie.
Я не проверял это на основе передовой практики, или что нужно, чтобы «надежно» идентифицировать пользователя снова. Но случайные данные не содержат ничего значимого, так что это не конец света, если плохой парень его захватит. Действительность захваченного файла cookie ограничена, и плохой парень должен имитировать среду пользователя довольно точно, если вы улавливаете соответствующие данные.
Почему hash имя пользователя? Это не секрет, и вам понадобится unhashed (или, по крайней мере, несогласованное) имя пользователя, чтобы в любом случае найти учетные данные для входа.
Кроме того, я думаю, вы захотите использовать криптозащитный RNG, такой как openssl_random_pseudo_bytes()
вместо rand()
. Кроме этого, основная идея выглядит нормально.
Если бы я был злонамеренным пользователем в открытой сети, например, точкой доступа wi-fi и хотел получить контроль над одной из учетных записей вашего пользователя, я мог бы попробовать следующие подходы. Защити себя.
Другой подход, который вы можете рассмотреть, – это сериализовать поля, зашифровать эту строку, а затем сохранить в кодировке base64 сообщение в вашем cookie. Кроме того, добавьте некоторую большую беспорядочную строку в вашу существующую соль.