#php #mysql #security
#php #mysql #Безопасность
Вопрос:
Перед вставкой данных в базу данных я зашифровал имя пользователя и пароль следующим образом:
$userName=strip_tags($userName);
$pass=strip_tags($pass);
$userName= htmlentities($userName, ENT_QUOTES, 'UTF-8');
$pass= htmlentities($pass, ENT_QUOTES, 'UTF-8');
$userName=mysql_real_escape_string($userName);
$pass=mysql_real_escape_string($pass);
$salt = 'SHIFLETT';
$password_hash = md5($salt . md5($pass.$salt));
Это было сделано для предотвращения SQL-атак и общих SQL-инъекций.
Теперь я хочу проверить пропуск и имя, которые пользователь дает мне при входе в систему. Я повторил тот же процесс экранирования удаления символов и экранирования специальных символов. Итак, вот моя функция для проверки прохождения:
function validateLogin($user_name, $pass)
{
$userName=strip_tags($userName);
$pass=strip_tags($pass);
$userName= htmlentities($userName, ENT_QUOTES, 'UTF-8');
$pass= htmlentities($pass, ENT_QUOTES, 'UTF-8');
$userName=mysql_real_escape_string($userName);
$pass=mysql_real_escape_string($pass);
$salt = 'SHIFLETT';
$password_hash = md5($salt . md5($pass.$salt));
$result=mysql_query("SELECT COUNT(*) AS Result FROM users WHERE user_name='$user_name' AND pass='$password_hash'");
mysql_close();
if($row=mysql_fetch_array($result))
{
if($row['Result']>0)
{
echo "Login successful";
}
else
{
echo "Login unsuccessful";
}
}
}
Мой вопрос заключается в том, будут ли работать проверки со всеми этими мерами безопасности? вернет ли MD5 тот же самый проход, если я использовал ту же кодировку MD5 для вставки, а затем для оператора select?
Комментарии:
1. md5 не является шифрованием.
2. Ваша соль должна быть уникальной для каждого пользователя и храниться в таблице вашей базы данных.
3. ну, злоумышленник не знает, что такое соль. соль должна быть каким-то дополнительным именем, «кодирующим» приложение .. не каждого отдельного пользователя
4. Использование соли помогает против предварительно вычисленных хэшей, другой хэш для каждого пользователя добавляет энтропии к вашим данным, больше энтропии = лучшая безопасность. Кроме того, md5 (или любой «быстрый» хэш) вреден для паролей, bcrypt — гораздо лучший вариант с точки зрения безопасности.
Ответ №1:
Для гибкости вам следует создать функцию для хэширования (а не шифрования) вашего пароля. Кроме того, используйте более сильный алгоритм, чем md5 (например, sha512, используемый в моем примере).
function hashPassword($str)
{
return hash("sha512", $str . "salt");
}
Я также рекомендую использовать mysql_real_escape_string
.
$password_hash = hashPassword($_POST['password']);
$username = mysql_real_escape_string($_POST['username']);
И вместо этого используйте auto_incremented int и выберите его.
mysql> create table users (
-> id int primary key auto_increment,
-> username varchar(20),
-> password char(128));
Затем просто сравните возвращенную строку с именем пользователя и паролем.
$check = "select id from users where username = '$username' and password = '$password_hash'";
$result = mysql_query($check);
if(mysql_num_rows($result))
{
echo "<p>Login was successful!</p>n";
}
Чтобы ответить на ваш вопрос: да, сравнение хэшированного пароля с хэшированной строкой в базе данных будет работать.
Комментарии:
1. хотя SHA512 может быть «сильнее», чем MD5 в качестве хэша, на самом деле это не лучший вариант для хеширования паролей. Он должен быть «быстрым», что помогает «плохим людям», когда дело доходит до грубой силы …. посмотрите в «bcrypt»: en.wikipedia.org/wiki/Bcrypt
2. @Nico Спасибо за ввод, криптография на самом деле не моя сильная сторона. Я думаю, я, должно быть, пропустил это, но я думаю, это понятно, поскольку, похоже, в PHP нет официальной функции для bcrypt. Тем не менее, я рассмотрю это.
3. Я очень давно не касался PHP, но я предполагаю, что это то, с чего я бы начал: openwall.com/phpass
Ответ №2:
Короткий ответ: да, он будет соответствовать
Длинный / лекционный ответ: md5 слабый, постоянная соль плохая, нет необходимости экранировать пароль перед хешированием и т. Д.
Комментарии:
1. Также ВЫБЕРИТЕ пароль ОТ пользователя, ГДЕ username = ‘something’ LIMIT 1; а затем сравните пароль базы данных с заданным паролем.
2. Но есть только один пароль, который соответствует. нет необходимости в ограничении 1. потому что существует только одно уникальное имя пользователя и один пароль. итак, если оно равно 1, это означает, что пользователь существует. Я не вижу, какой предел 1 добавит
3.
LIMIT 1
полезно, если у вас нетUNIQUE
индекса для имени пользователя, поскольку он сообщает MySQL прекратить поиск после того, как он найдет один результат. В противном случае он продолжит обход таблицы.
Ответ №3:
$pass=mysql_real_escape_string($pass);
довольно избыточно. Даже если пароль содержит метасимвол SQL (например, a '
), он все равно исчезнет после того, как вы запустите пароль через md5. Все, что это сделало бы, это добавило дополнительный символ в строку пароля для каждого экранируемого символа, так что это было бы своего рода псевдосаливкой.
Но в остальном, да… до тех пор, пока вы выполняете один и тот же md5 / солевой процесс для паролей везде, где они используются, и сохраняете / сравниваете только полученный хэш в базе данных, тогда ваши сравнения будут действительными.
Ответ №4:
Этот вопрос несколько устарел, но теперь есть лучшие альтернативы с php 5.5. Приведенный выше код больше не нужен. Php 5.5 позволяет легко создавать встроенную защиту паролем. И это почти тупое доказательство. http://www.php.net/manual/en/function.password-hash.php Как вы можете видеть, просто используя
password_hash("yourpass", PASSWORD_DEFAULT)
Вы используете как случайную соль, так и bcrypt одновременно. Если вы не обновились до последних версий php, я бы посоветовал сделать это сейчас.