LINUX.ORG.RU

Нормальная аутентификация на php+mysql+cookies

 , , ,


1

1

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

Для каждого пользователя системы в mysql-табличке хранится логин, хэш-пароля(от соли) и сама соль. Также есть пустые поля под CURRENT_IP, CURRENT_USER_AGENT и CURRENT_HASH.

При заходе на страничку login.php пользователь вводит свои логин и пароль;
Логин и пароль обрабатываем preg_match - проверяем, чтобы были только буквы и цифры;
Делаем запрос к базе через adodb (там есть плейсхолдеры);
Если есть такой логин, берем из базы соль, хэшируем соль+пользовательский пароль, проверяем совпадение получившегося хэша с хэшем из базы;
Если всё окей, создаем CURRENT_HASH - любая строка, например md5(time() + "123"), заносим её в базу и кладем в $_COOKIES. Также заносим в базу CURRENT_IP = текущий адрес пользователя и CURRENT_USER_AGENT = md5(от текущего значения user-agent пользователя);


При заходе на любую страницу сайта (где требуется авторизация) подключаем файл auth.php со следующим содержимым:

$my_current_hash = $_COOKIES['CURRENT_HASH']

$sql = "
SELECT `USER_ID`, `CURRENT_HASH`, `CURRENT_USER_AGENT`, INET_NTOA(`CURRENT_IP`) as `CURRENT_IP_NTOA`
FROM `users`
WHERE (`CURRENT_HASH` = %s") AND (`CURRENT_IP_NTOA` = %s)
		AND (`CURRENT_USER_AGENT` = %s);
// fetchRow из adodb
$res = fetchRow($sql, $my_current_hash, $_SERVER['REMOTE_ADDR'],
	md5($_SERVER['HTTP_USER_AGENT']));

if ($res)
	echo "success";
else {
	Header('location: you_suck.php');
	exit();
}

Достаточно ли такого подхода для обеспечения безопасности веб-приложения?



Последнее исправление: Klymedy (всего исправлений: 1)

хэшируем соль+пользовательский пароль

чем хешануть собрался?

Od1n
()

В приведённом коде ошибка - двойную кавычку не там закрыл.

Алсо, ты говоришь, что используешь плейсхолдеры, а в приведенном коде %s. Стоило уточнить, что ты под плейсхолдерами понимаешь не бд-шные '?'.

Также не вижу большого смысла разделять current_hash и current_user_agent - легче их объединить, а не хранить двумя полями.

Также такое поле c IP адресом, обычно, принято именовать last ip, а не current. Ну ты понимаешь, соединение - вещь не постоянная, поэтому ip не может быть текущим.

Od1n
()
Ответ на: комментарий от Od1n

чем хешануть собрался?

md5($salt+md5($pwd))

Также не вижу большого смысла разделять current_hash и current_user_agent

current_user_agent - защита от подстановки куки в другой браузер. При каждой авторизации (неважно какого пользователя) через этот один и тот же браузер оно будет одинаково. А current_hash - генерируется новый для каждой авторизации даже через один и тот же браузер.
Получается защита от украденного хэша - не подойдет юзерагент и/или айпи-адрес.

принято именовать last ip, а не current

Спасибо!

JANB
() автор топика
Ответ на: комментарий от Od1n

Алсо, ты говоришь, что используешь плейсхолдеры, а в приведенном коде %s

Сорри, конечно же '?', код не скопированный, только что набрал. Поэтому же двойная кавычка не закрыта.

JANB
() автор топика
Ответ на: комментарий от Od1n

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

JANB
() автор топика

В Мускуле уже есть встроенная функция password. Можешь ее использовать, чтоб с хешированием пароля самому не мучаться.

ovax ★★★
()
Ответ на: комментарий от e1nste1n

Спасибо! Вторая ссылка классная.

JANB
() автор топика
Ответ на: комментарий от ritsufag

Ну я бы не сказал, что мало. Там есть куча всего. Тебе остаётся только написать провайдер для своего хранилища и реализовать контроллеры. А если хорошо поискать, то можно найти готовые решения.

Я не нашел ничего в предложенной тобой либе из того, чего не умел бы симфониевский компонент. Он гораздо функциональнее будет. Но и сложнее в разы.

Kilte ★★★★★
()
Ответ на: комментарий от JANB

md5($salt+md5($pwd))

md5 разве не самый слабый из алгоритмов хеширования?

Qwentor ★★★★★
()
Ответ на: комментарий от ritsufag

Я подумал, что это можно отдельно без ларавела использовать. А оно оказывается вшито туда. Но в таком случае, я полагаю, что у автора уже есть свои наработки и ему вряд ли захочется переписывать всё на ларавел.

Kilte ★★★★★
()
Ответ на: комментарий от ritsufag

Ну и вот собственно, прикрутить авторизацию не составит никакого труда. Есть провайдер для Silex, есть standalone провайдер для Security, есть еще бандл для симфони, над которым надо будет наверное написать обёртку, чтобы отдельно от симфони его завести. А дальше вот:

    $app->register(
        new SecurityServiceProvider(),
        [
            'security.firewalls' => [
                'admin' => [
                    'pattern' => '^/',
                    'http' => true,
                    'users' => [
                        'admin' => ['ROLE_ADMIN', $passwd]
                    ],
                    'anonymous' => true
                ]
            ],
            'security.access_rules' => [
                ['^/admin', 'ROLE_ADMIN'],
            ]
        ]
    );
В итоге имеем в считанные секунды годную защиту с авторизацией по http. Если немного покурить доки, то можно получить и ACL и форму логина прикрутить и еще тысячи фич. А самое главное, это легко интегрируется в любой проект.

Kilte ★★★★★
()

В принципе, всё верно.

md5 замени на bcrypt

Если тебе нужна рандомная строка для криптографических целей - используй не md5(time), а openssl_random_pseudo_bytes

Kesha_Molchanov
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.