Подтвердить что ты не робот

Существуют ли уязвимости в этом PHP-коде?

Я только что получил сайт для управления, но не слишком уверен в коде, о котором писал предыдущий парень. Я вставляю процедуру входа в систему ниже, не могли бы вы взглянуть и сказать, есть ли какие-либо уязвимости в системе безопасности? На первый взгляд кажется, что можно проникнуть через SQL-инъекцию или манипулировать куки файлами и параметр? M =.


define ( 'CURRENT_TIME', time ()); / / Current time. 
define ( 'ONLINE_TIME_MIN', (CURRENT_TIME - BOTNET_TIMEOUT)); / / Minimum time for the status of "Online". 
define ( 'DEFAULT_LANGUAGE', 'en'); / / Default language. 
define ( 'THEME_PATH', 'theme'); / / folder for the theme. 

/ / HTTP requests. 
define ( 'QUERY_SCRIPT', basename ($ _SERVER [ 'PHP_SELF'])); 
define ( 'QUERY_SCRIPT_HTML', QUERY_SCRIPT); 
define ( 'QUERY_VAR_MODULE', 'm'); / / variable contains the current module. 
define ( 'QUERY_STRING_BLANK', QUERY_SCRIPT. '? m ='); / / An empty query string. 
define ( 'QUERY_STRING_BLANK_HTML', QUERY_SCRIPT_HTML. '? m ='); / / Empty query string in HTML. 
define ( 'CP_HTTP_ROOT', str_replace ( '\ \', '/', (! empty ($ _SERVER [ 'SCRIPT_NAME'])? dirname ($ _SERVER [ 'SCRIPT_NAME']):'/'))); / / root of CP. 

/ / The session cookie. 
define ( 'COOKIE_USER', 'p'); / / Username in the cookies. 
define ( 'COOKIE_PASS', 'u'); / / user password in the cookies. 
define ( 'COOKIE_LIVETIME', CURRENT_TIME + 2592000) / / Lifetime cookies. 
define ( 'COOKIE_SESSION', 'ref'); / / variable to store the session. 
define ( 'SESSION_LIVETIME', CURRENT_TIME + 1300) / / Lifetime of the session. 

////////////////////////////////////////////////// ///////////////////////////// 
/ / Initialize. 
////////////////////////////////////////////////// ///////////////////////////// 

/ / Connect to the database. 
if (! ConnectToDB ()) die (mysql_error_ex ()); 

/ / Connecting topic. 
require_once (THEME_PATH. '/ index.php'); 

/ / Manage login. 
if (! empty ($ _GET [QUERY_VAR_MODULE])) 
( 
  / / Login form. 
  if (strcmp ($ _GET [QUERY_VAR_MODULE], 'login') === 0) 
  ( 
    UnlockSessionAndDestroyAllCokies (); 

    if (isset ($ _POST [ 'user']) & & isset ($ _POST [ 'pass'])) 
    ( 
      $ user = $ _POST [ 'user']; 
      $ pass = md5 ($ _POST [ 'pass']); 

      / / Check login. 
      if (@ mysql_query ( "SELECT id FROM cp_users WHERE name = '". addslashes ($ user). "' AND pass = '". addslashes ($ pass). "' AND flag_enabled = '1 'LIMIT 1") & & @ mysql_affected_rows () == 1) 
      ( 
        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); 
        ) 

        LockSession (); 
        $ _SESSION [ 'Name'] = $ user; 
        $ _SESSION [ 'Pass'] = $ pass; 
        / / UnlockSession (); 

        header ( 'Location:'. QUERY_STRING_BLANK. 'home'); 
      ) 
      else ShowLoginForm (true); 
      die (); 
    ) 

    ShowLoginForm (false); 
    die (); 
  ) 

  / / Output 
  if (strcmp ($ _GET [ 'm'], 'logout') === 0) 
  ( 
    UnlockSessionAndDestroyAllCokies (); 
    header ( 'Location:'. QUERY_STRING_BLANK. 'login'); 
    die (); 
  ) 
) 

////////////////////////////////////////////////// ///////////////////////////// 
/ / Check the login data. 
////////////////////////////////////////////////// ///////////////////////////// 

$ logined = 0, / / flag means, we zalogininy. 

/ / Log in session. 
LockSession (); 
if (! empty ($ _SESSION [ 'name']) & &! empty ($ _SESSION [ 'pass'])) 
( 
  if (($ r = @ mysql_query ( "SELECT * FROM cp_users WHERE name = '". addslashes ($ _SESSION [' name'])."' AND pass = ' ". addslashes ($ _SESSION [' pass']). " 'AND flag_enabled = '1' LIMIT 1 ")))$ logined = @ mysql_affected_rows (); 
) 
/ / Login through cookies. 
if ($ logined! == 1 & &! empty ($ _COOKIE [COOKIE_USER]) & &! empty ($ _COOKIE [COOKIE_PASS])) 
( 
  if (($ r = @ mysql_query ( "SELECT * FROM cp_users WHERE MD5 (name )='". addslashes ($ _COOKIE [COOKIE_USER ])."' AND pass = '". addslashes ($ _COOKIE [COOKIE_PASS]). " 'AND flag_enabled = '1' LIMIT 1 ")))$ logined = @ mysql_affected_rows (); 
) 
/ / Unable to login. 
if ($ logined! == 1) 
( 
  UnlockSessionAndDestroyAllCokies (); 
  header ( 'Location:'. QUERY_STRING_BLANK. 'login'); 
  die (); 
) 

/ / Get the user data. 
$ _USER_DATA = @ Mysql_fetch_assoc ($ r); 
if ($ _USER_DATA === false) die (mysql_error_ex ()); 
$ _SESSION [ 'Name'] = $ _USER_DATA [ 'name']; 
$ _SESSION [ 'Pass'] = $ _USER_DATA [ 'pass']; 

/ / Connecting language. 
if (@ strlen ($ _USER_DATA [ 'language'])! = 2 | |! SafePath ($ _USER_DATA [ 'language']) | |! file_exists ( 'system / lng .'.$_ USER_DATA [' language '].' . php'))$_ USER_DATA [ 'language'] = DEFAULT_LANGUAGE; 
require_once ( 'system / lng .'.$_ USER_DATA [' language'].'. php '); 

UnlockSession (); 
4b9b3361

Ответ 1

Да, в этом коде есть несколько уязвимостей.

Это может быть проблемой:

define ( 'QUERY_SCRIPT', basename ($ _SERVER [ 'PHP_SELF'])); 

PHP_SELF плохо, потому что злоумышленник может управлять этой переменной. Например, попробуйте распечатать PHP_SELF при доступе к script с этим URL: http://localhost/index.php/test/junk/hacked. Избегайте этой переменной, насколько это возможно, если вы ее используете, убедитесь, что вы ее дезинфицируете. Очень часто можно увидеть, как XSS возникает при использовании этой переменной.

1-я уязвимость:

setcookie (COOKIE_USER, md5 ($ user), COOKIE_LIVETIME, CP_HTTP_ROOT); 
setcookie (COOKIE_PASS, $ pass, COOKIE_LIVETIME, CP_HTTP_ROOT); 

Это довольно серьезная уязвимость. Если у злоумышленника была SQL-инъекция в вашем приложении, они могли бы получить хеш-память md5, а также имя пользователя и логин сразу, не нарушая хеш < <25 > . Это как будто вы храните пароли в ясном тексте.

Эта уязвимость сеанса в два раза, это также "бессмертный сеанс", идентификатор сеанса всегда должен быть большим случайным образом сгенерированным значением, которое истекает. Если они не истекают, то они намного легче использовать грубую силу.

Вы должны НИКОГДА повторно изобретать колесо, вызовите session_start() в самом начале вашего приложения, и это автоматически сгенерирует защищенный идентификатор сеанса, который истекает. Затем используйте переменную сеанса, например $_SESSION['user'], чтобы отслеживать, если браузер действительно зарегистрирован.

Вторая уязвимость:

$ pass = md5 ($ _POST [ 'pass']);

md5() доказано, что он небезопасен, поскольку коллизии были преднамеренно созданы. md5() должен использоваться никогда для паролей. Вы должны использовать члена семейства sha2, sha-256 или sha-512 - отличный выбор.

Третья уязвимость:

CSRF

Я не вижу никакой защиты CSRF для вашей логики аутентификации. Я подозреваю, что все запросы в вашем приложении уязвимы для CSRF.

Ответ 2

Принятый ответ пропускает много и неправильно о некоторых вещах. Вот уязвимости, которые я вижу в коде:

define('QUERY_SCRIPT', basename($_SERVER['PHP_SELF']));

Как сказано в другом месте, это может содержать больше, чем просто путь script. Вместо этого используйте $_SERVER['SCRIPT_NAME'] или __FILE__.

define('CP_HTTP_ROOT', ...

Эта константа используется для установки пути cookie к пути script. Это небезопасно, но пользователю нужно будет входить в систему отдельно для каждого script. Вместо этого используйте сеансы (обсужденные ниже) и установите один базовый путь для своего приложения.

UnlockSessionAndDestroyAllCokies()

Я не знаю точно, что это делает, но это звучит не очень хорошо. Просто запустите сеанс в начале script для каждого запроса. Проверьте наличие существующей пользовательской информации в сеансе, чтобы узнать, вошли ли они в систему.

$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-инъекций. Использовать подготовленные операторы или, по крайней мере, функции escape-последовательности библиотеки.

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 с ответом. Они могут быть легко прочитаны и использованы сторонним лицом. Поскольку этот script использует простой хеш, таблица радуги позволит кому-то найти многие пароли пользователей. Но поскольку ответ содержит "защищенные" учетные данные, злоумышленнику не нужно ничего делать, кроме как передавать их в любой другой запрос на вход в систему. Это не правильный способ "запомнить" пользователя и не нужен.

Пользовательское соединение с запросом должно обрабатываться только в сеансе. Это их цель. Запросы и ответы содержат файл 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();

Снова я не знаю, что это делает, но в конце script сеанс должен просто записываться в хранилище.