Г-код

Zavus

Новичок
Люди, пытался написать свою первую систему защиты от брута. Суть в том, чтобы
после первой неудачной попытки авторизации , для конкретного логина
показывалась капча в течение N-ного времени.

Вроде работает именно так, как я хотел. Но код выглядит... Короче не очень выглядит. Выложил его ниже.

Сразу скажу, что я буду делать обработку ошибок, отделение логики от представления и тд.
И еще там много необъяснимой дичи , тупых комментариев, все это подправлю. Также нет реальной капчи и ее реальной проверки. Пока для примера просто сделал текстовое поле. И еще всякие $pattern['password] ' :eek:

Но , что-то меня настораживает ветвление условий.
например, конструкции типа
Если что-то не так, то формирую ошибку , редирект и выхожу из программы .

Как тут

Код:
 if (!isset($_SESSION['show_captcha'])){
    $_SESSION['show_captcha'] = 1;
    $_SESSION['captcha_error'] = 'Ошибка: Введите капчу B. <br/>';
    header('Location:authentification.php');
    exit();
}

Можно ли так делать? Считается ли это нормальным стилем?

Ну и собственно, вот.
Код:
<?php
error_reporting(E_ALL);
session_start();
if (isset($_SESSION['captcha_error'])){
    echo $_SESSION['captcha_error'];
  
    unset($_SESSION['captcha_error']);
}

if (isset($_SESSION['bad_data'])){
  
    echo $_SESSION['bad_data'];
  
    unset($_SESSION['bad_data']);
}
?>

<form action = 'authentification.php' method = 'POST'>

<input type = 'text' maxlength = '32' name = 'email' /> Введите email <br/>
<input type = 'password' maxlength = '32' name = 'password' /> Введите пароль <br/>

<?php
if (isset($_SESSION['show_captcha'])){
    echo "<input type = 'text' maxlength = '10' name = 'captcha' value ='CAPTCHA' /> Введите капчу <br/>";
}
?>

<input type = 'submit' name = 'submit' value =  'Войти' /><br/>
</form>
<br/>
<br/>

<?php

  
//Если был отправлен пост-запрос на этот скрипт...
if(strtoupper($_SERVER['REQUEST_METHOD']) === 'POST'){
    
     print_r($_POST);
    //Проверяем, все ли требуемые поля вообще существуют, и если нет - критическая ошибка
    $required_fields = array('email','password');
  
    foreach($required_fields as $key){
        if (!isset($_POST[$key])){
            //$critical_error = true;
            //header('location:404.html');
            //редиррект на страницу 404
            echo 'Критическая ошибка: не существует нужных полей!.<br/> ';
        }
    }
  
    /* т.к. при регистрации данные пользователя проверяютя на регулярные выражения, это значит, что в базе не может быть этих
    самых неправильных значений.
  
    Если пользователь при аутентификации вводит данные, не соответствующие этим регуляркам - мы можем быть уверены, что
    в базе нет совпадений по этим данным  и сразу выводим соответствущее сообщение
    Даже если в базе и есть неправильные данные (допущенные по ошибке администратора БД или злоумышленнику удалось как-то их
    ввести ), то по ним мы все равно не должны пускать пользователя.  */
/*     $pattern = array();
  
    $pattern['password'] = '/^[a-zA-Z0-9]{6,32}$/';
    $pattern['email'] = '/.+@.+\..+/i';
  
    $_POST['email'] = trim($_POST['email']);
  
  
    if ($_POST['email'] === ''){
        echo "Введите email ";
    }
  
    if (trim($_POST['password'] === '')){
        echo "Введите Пароль ";
    }
  
    if (
    !preg_match($pattern['password'], $_POST['password'])
    || !preg_match($pattern['email'], $_POST['email'])
    ){
        echo "Такого пользователя не существует";
        exit();
    } */
  
     //Подключение к БД
    $db_host = "localhost";
    $db_username = "root";
    $db_password = "2230200";
    $db_name = "dota_guides";
    $link= mysqli_connect($db_host, $db_username, $db_password, $db_name) or die(mysqli_error($link));
    if (!$link) {
       echo mysqli_connect_error();
    }
  
    if (isset($_SESSION['show_captcha'])){
        echo "123<br/>";
        if (!isset($_POST['captcha']) || trim($_POST['captcha'])==='' ){
            $_SESSION['captcha_error'] = 'Ошибка: Введите капчу A. <br/>';
        }
        elseif($_POST['captcha'] !== 'CAPTCHA'){
            $_SESSION['captcha_error'] = 'Ошибка: Капча введена неверно. <br/>';
        }
      
        if (isset($_SESSION['captcha_error'])){
                header('Location:authentification.php');
                exit();
        }
    }
  
$stmt = mysqli_prepare($link, 'SELECT id , password,  captcha_date FROM users WHERE email=? LIMIT 1');
    mysqli_stmt_bind_param($stmt, "s",  $_POST['email']);
    mysqli_stmt_execute($stmt);
    mysqli_stmt_store_result($stmt);
  
    mysqli_stmt_bind_result($stmt, $user_id, $stored_password,  $captcha_date);
    mysqli_stmt_fetch($stmt);
  
    if (mysqli_stmt_num_rows($stmt) > 0){
          
        $captcha_lifetime =  43200; // срок показа капчи - 12 часов (60*60*12)
        $difference = time() - $captcha_date;
      
           if( $difference < $captcha_lifetime ) {
          
            if (!isset($_SESSION['show_captcha'])){
                $_SESSION['show_captcha'] = 1;
                $_SESSION['captcha_error'] = 'Ошибка: Введите капчу B. <br/>';
                 header('Location:authentification.php');
                exit();
            }
          
        }
          
        mysqli_stmt_close($stmt);
      
        $salt = $_POST['email'];
        $password = md5($_POST['password'].$salt);
      
        if($password !== $stored_password){
          
          
            if ($difference > $captcha_lifetime){
                $stmt = mysqli_prepare($link, 'UPDATE users SET  captcha_date = ?  WHERE id =? LIMIT 1');
                mysqli_stmt_bind_param($stmt, "ii",  time(), $user_id );
                mysqli_stmt_execute($stmt);   
                mysqli_stmt_close($stmt);
            }
          
             $_SESSION['bad_data'] = 'Ошибка. Неправильный email или пароль A.<br/>';
             $_SESSION['show_captcha'] = 1;
            header('Location:authentification.php');
            exit();
        }
        else{
          
            unset($_SESSION['show_captcha']);
          
            if( $difference < $captcha_lifetime ) {
                $stmt = mysqli_prepare($link, 'UPDATE users SET  captcha_date = 0  WHERE id =? LIMIT 1');
                mysqli_stmt_bind_param($stmt, "i",  $user_id );
                mysqli_stmt_execute($stmt);   
                mysqli_stmt_close($stmt);
            }
          
            //оповещаем пользователя об успехе аторизации, создаем его переменне сессии и тд.
            echo 'вы успешно авторизировались! <br/>';
            unset($_SESSION['show_captcha']);
          
        }
      
    }
    else{
      
         $_SESSION['show_captcha'] = 1;
         $_SESSION['bad_data'] = 'Ошибка. Неправильный email или пароль B.<br/>';
            header('Location:authentification.php');
            exit();
    }
  
}
?>

Скажите, можно ли тут что-то вообще понять?

И если можно, то подскажите, такая защита нормальная? Дыр нет?
 
Последнее редактирование:

WMix

герр M:)ller
Партнер клуба
Когда сессия это просто, те кто захочет положить сайт будут без кук, он отдаст запрос долгому скрипту и не дождавшись ответа сделает еще 20 запросов, при этом ip может меняться прячась за проксями (это как усложнение). так что думай заного...
 

Zavus

Новичок
Когда сессия это просто, те кто захочет положить сайт будут без кук, он отдаст запрос долгому скрипту и не дождавшись ответа сделает еще 20 запросов, при этом ip может меняться прячась за проксями (это как усложнение). так что думай заного...
Чет я не понял(

У меня же безопасность на куках и сессиях не держится, на них только вывод поля ввода капчи держится.
 

sanmai

Новичок
Стоило бы фиксировать число заходов с логином в БД.
При превышении числа ошибочных заходов, например, за последний час, показывать капчю при любых попытках входа.

В сессии при этом будет храниться только отметка о том, что капча была разгадана, которая сбрасывается при очередном неудачном вводе пароля.
 
Сверху