В принятом ответе много пропущено и неправильно в некоторых вещах. Вот уязвимости, которые я вижу в коде:
define('QUERY_SCRIPT', basename($_SERVER['PHP_SELF']));
Как уже было сказано, это может содержать не только путь к сценарию. Вместо этого используйте $_SERVER['SCRIPT_NAME']
или __FILE__
.
define('CP_HTTP_ROOT', ...
Эта константа используется для установки пути к файлу cookie к пути к скрипту. Это небезопасно, но пользователь должен будет войти в систему отдельно для каждого сценария. Вместо этого используйте сеансы (обсуждаемые ниже) и установите один базовый путь для вашего приложения.
UnlockSessionAndDestroyAllCokies()
Я не знаю точно, что это делает, но звучит не очень хорошо. Просто запустите сеанс в начале скрипта для каждого запроса . Проверьте информацию о существующих пользователях в сеансе, чтобы узнать, не вошли ли они в систему.
$pass = md5($_POST['pass']);
Пароли должны иметь уникальную соль с каждым хешем, и желательно использовать лучший алгоритм хеширования. В эти дни (PHP 5.5+) вы должны использовать password_hash
и password_verify
, чтобы позаботиться о деталях хеширования пароля.
mysql_query("SELECT id FROM cp_users WHERE name = '". addslashes($user)...
Это старый вопрос, но сегодня функции mysql_
PHP больше не поддерживаются. Используйте mysqli
или PDO. Использование неподдерживаемой библиотеки оставляет вас открытыми для незащищенных уязвимостей . addslashes
не является идеальной защитой от внедрения SQL. Используйте подготовленные операторы или хотя бы строковые функции библиотеки.
if (isset($_POST['remember']) && $_POST['remember'] == 1)
(
setcookie(COOKIE_USER, md5($user), COOKIE_LIVETIME, CP_HTTP_ROOT);
setcookie(COOKIE_PASS, $pass, COOKIE_LIVETIME, CP_HTTP_ROOT);
)
А вот и самая большая проблема. Файлы cookie хранят учетные данные пользователя . Вы отправляете обратно хэшированное имя пользователя и хэшированный пароль в виде значений cookie вместе с ответом. Они могут быть легко прочитаны и использованы третьей стороной. Поскольку в этом скрипте используется простой хеш, радужная таблица позволяет кому-то искать многие пароли пользователей. Но поскольку ответ содержит «защищенные» учетные данные, злоумышленнику не нужно будет ничего делать, кроме как передать их в любой другой запрос на вход в систему. Это не правильный способ «запомнить» пользователя и не требуется.
Подключение пользователя к запросу должно обрабатываться только в сеансе. Это их цель. Запросы и ответы содержат cookie со случайным идентификатором. Данные пользователя остаются только на сервере и ссылаются на этот идентификатор. (Примечание: есть ошибка, что этот блок заключен в скобки вместо фигурных скобок.)
$_SESSION['Pass'] = $pass;
Теперь пароль пользователя хранится в двух местах : база данных и хранилище сеансов. Если сеансы хранятся вне базы данных (а PHP по умолчанию сохраняет их на диске), у вас есть два способа, которыми кто-то может попытаться украсть учетные данные пользователя.
if ($logined !== 1 && !empty($_COOKIE[COOKIE_USER]) ...
if (($r = @mysql_query("SELECT * FROM cp_users WHERE MD5(name)='". addslashes($_COOKIE [COOKIE_USER ])."' AND pass = '". addslashes($_COOKIE [COOKIE_PASS])..
Злоумышленник может теперь попытаться войти в систему, просто передав заголовки cookie в запросе с хэшем md5 имени пользователя и пароля, который был передан им в предыдущем ответе. Форма входа должна быть единственным местом, где можно получить учетные данные пользователя и войти в них. Эта форма (и все остальные) должна использовать токен CSRF.
UnlockSession();
Опять же, я не знаю, что это делает, но в конце скрипта сессия должна быть просто записана в хранилище.