(PHP) Проверка, безопасность и скорость - есть ли в моем приложении такие? - PullRequest
0 голосов
/ 17 ноября 2009

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

В любом случае, вот пример того, что я позволил своему приложению. делать: Рассмотрим страницу (register.php), в которой есть форма, в которой у пользователя есть 3 поля для заполнения, например: имя, фамилия и адрес электронной почты. После отправки этой формы я хочу проверить форму и показать пользователям соответствующие ошибки:

<form id="form1" name="form1" method="post" action="<?php echo $_SERVER['PHP_SELF']; ?>"> 

<label for="name">Name:</label>  
<input type="text" name="name" id="name" /><br />

<label for="lname">Last Name:</label>   
<input type="text" name="lname" id="lname" /><br />

<label for="email">Email:</label>   
<input type="text" name="email" id="email" /><br />


<input type="submit" name="submit" id="submit" value="Submit" />
</form>

Эта форма будет размещать информацию на той же странице. Итак, вот код, который будет обрабатывать информацию POST:

<?php

require("functions.php");

if( isset($_POST['submit']) )
    {
        $errors = fn_register();

        if( count($errors) )
        {
            //Show error messages
        }
        else
        {
            //Send welcome mail to the user or do database stuff...
        }

    }

?>




<?php

//functions.php page:

function sql_quote( $value )
{
     if( get_magic_quotes_gpc() )
    {

          $value = stripslashes( $value );
    }
    else
    { 
          $value = addslashes( $value );
    } 
    if( function_exists( "mysql_real_escape_string" ) )
    {
          $value = mysql_real_escape_string( $value );
    }

    return $value;

}


function clean($str) {
$str = strip_tags($str, '<br>,<br />');
$str = trim($str);
$str = sql_quote($str); 

return $str;

}


 foreach ($_POST as &$value)  
    {
               if (!is_array($value)) 
        { 
                       $value = clean($value); 

               }
               else 
        { 
                       clean($value);
               }
       }

 foreach ($_GET as &$value)  
    {
               if (!is_array($value)) 
        { 
                       $value = clean($value); 
               }
               else 
        { 
                       clean($value);
               }
       } 


function validate_name( $fld, $min, $max, $rule, $label ) {

    if( $rule == 'required' ) 
    {    
        if ( trim($fld) == '' ) 
        {
            $str = "$label: Cannot be left blank.";
            return $str;
        }        
    }


    if ( isset($fld) && trim($fld) != '' ) 
    {    
        if ( isset($fld) && $fld != '' && !preg_match("/^[a-zA-Z\ ]+$/", $fld)) 
    {
            $str = "$label: Invalid characters used! Only Lowercase, Uppercase alphabets and Spaces are allowed";
        }

    else if ( strlen($fld) < $min or strlen($fld) > $max )  
    {
            $curr_char = strlen($fld);
            $str = "$label: Must be atleast $min character &amp; less than $max char. Entered characters: $curr_char";
        }
        else    
        {
            $str = 0;
        }        
    }
    else
    {
        $str = 0;
    }

    return $str;   
}


function validate_email( $fld, $min, $max, $rule, $label ) {

    if( $rule == 'required' ) 
    {    
        if ( trim($fld) == '' ) 
        {
            $str = "$label: Cannot be left blank.";
            return $str;
        }        
    }


    if ( isset($fld) && trim($fld) != '' ) 
    {    
        if ( !eregi('^[a-zA-Z0-9._-]+@[a-zA-Z0-9._-]+\.([a-zA-Z]{2,4})$', $fld) ) 
    {
            $str = "$label: Invalid format. Please check.";
        }
    else if ( strlen($fld) < $min or strlen($fld) > $max )  
    {
            $curr_char = strlen($fld);
            $str = "$label: Must be atleast $min character &amp; less than $max char. Entered characters: $curr_char";
        }
        else    
        {
            $str = 0;
        }        
    }
    else
    {
        $str = 0;
    }

    return $str;   
}

function val_rules( $str, $val_type, $rule='required' ){

    switch ($val_type) 
    {
        case 'name':
                $val = validate_name( $str, 3, 20, $rule, 'First Name');
        break;

        case 'lname':
                $val = validate_name( $str, 10, 20, $rule, 'Last Name');
        break;        

        case 'email':
                $val = validate_email( $str, 10, 60, $rule, 'Email');
        break;


    }

    return $val;
}


function fn_register() {

    $errors = array();

    $val_name        = val_rules( $_POST['name'], 'name' );
    $val_lname           = val_rules( $_POST['lname'], 'lname', 'optional' );
    $val_email       = val_rules( $_POST['email'], 'email' );

    if ( $val_name != '0' )         { $errors['name']   = $val_name;  }
    if ( $val_lname != '0' )        { $errors['lname']  = $val_lname; }
    if ( $val_email != '0' )        { $errors['email']  = $val_email; }

     return $errors;
}

//END of functions.php page
?>

Хорошо, теперь это может показаться, что есть много, но позвольте разбить это на части:

  1. Я хотел, чтобы циклы foreach ($ _POST как & $ value) и foreach ($ _GET as & $ value) циклически просматривали полученную информацию из пользовательской отправки и удаляли / удаляли весь вредоносный ввод.
  2. Сначала я вызываю функцию с именем clean на входе для достижения цели, как указано выше. Эта функция будет обрабатывать каждый из входных данных, будь то отдельные значения полей или даже массивы, разрешать только теги
    и удалять все остальное. В остальном это очевидно.
  3. Как только это произойдет, новые / очищенные значения будут обработаны функцией fn_register () и на основе значений, возвращенных после проверки, мы получим соответствующие ошибки или значения NULL (в зависимости от обстоятельств).

Итак, вот мои вопросы:

  1. Это в значительной степени заставляет меня чувствовать себя в безопасности, поскольку я заставляю пользователя исправлять вредоносные данные и не будет обрабатывать окончательные данные, пока ошибки не будут исправлены. Я прав?

  2. Гарантирует ли метод, которым я следую, скорость (так как я использую множество функций и их соответствующие вызовы)? Поля формы различаются, и минимальное количество полей, которые я могу иметь в любой данный момент времени в любой форме, может быть 3 и может доходить до 100 (или даже больше, я не уверен, так как сайт все еще работает разработаны). Снизит ли скорость применения приложения наличие сотен полей и их проверка указанным выше способом (скажем, до полумиллиона пользователей одновременно получают доступ к веб-сайту?). Что я могу сделать, чтобы повысить скорость и уменьшить количество вызовов функций (если это возможно)?

  3. Могу ли я сделать что-то, чтобы улучшить существующие способы проверки?

Я сдерживаю объектно-ориентированный подход и использую FILTERS в PHP для дальнейшего использования. Поэтому, пожалуйста, я прошу вас всех предложить мне способ улучшить / настроить текущие способы и предложить мне, является ли сценарий уязвимым или достаточно безопасным для использования в среде реального производства. Если нет, что я могу сделать, чтобы использовать его вживую?

Ответы [ 2 ]

0 голосов
/ 15 апреля 2010

Ваш скрипт уязвим для межсайтовых скриптовых атак в первой строке. Значение $ _SERVER ['PHP_SELF'] не может быть доверенным. Вы должны отфильтровать это. Вот простое исправление:

<form id="form1" name="form1" method="post" action="<?php echo htmlspecialchars($_SERVER['PHP_SELF'], ENT_QUOTES, 'utf-8'); ?>"> 

при необходимости замените UTF-8 другой кодировкой.

Вы можете попробовать ввести как

http://site.com/page.php?a=%22onload%3D%22javascript%3Aalert('XSS')%22

против вашего сайта, чтобы увидеть, появляется ли на нем предупреждение.

Обновление: кажется, что по крайней мере в PHP 5.3 ваш фрагмент кода не уязвим для XSS. Однако я не могу гарантировать (как и вы), что PHP_SELF будет производить в более старых версиях PHP или в будущем. Значение PHP_SELF должно быть закодировано.

0 голосов
/ 17 ноября 2009

Чтобы ответить на ваши вопросы:

  1. При краткой проверке похоже, что ваш код удалит вредоносные данные. Если вы убедитесь, что ваш код разбит на небольшие функции, которые работают только со значениями, передаваемыми в них в качестве аргументов, вы можете написать себе набор тестов на основе командной строки, который позволяет создавать множество тестовых примеров, которые вы можете повторно запускать каждый раз, когда вы вносите изменения в систему, чтобы быть уверенными в отсутствии уязвимостей.
  2. В общем, самая медленная часть любого веб-приложения - это слой базы данных. Плохо созданные запросы и / или слишком много запросов в подавляющем большинстве будут затенять выполнение кода PHP с точки зрения проблем производительности. Другими словами, не беспокойтесь о чрезмерной оптимизации вашего PHP-кода.
  3. Лично я бы улучшил ваш код, обернув все в функцию (). Я бы также очищал значения $_POST и $_GET по мере необходимости, а не все сразу. Другими словами, я бы назвал clean() на $str в val_rules(). Кроме того, меня очень смущает использование include() или require() для извлечения сценария, а затем осознание того, что этот сценарий выполняется и выполняет некоторую функцию «за кулисами». Я думаю, вы обнаружите, что использование include() или require() работает лучше всего, когда извлекаемые файлы просто используются для объявления функций, констант и классов. Важно иметь возможность четко следить за всем выполнением «открыто», то есть на странице, которая фактически выполняет какую-то работу. Точно так же я бы не позволил функции fn_register() напрямую обращаться к массиву $_POST, не передавая это вместо аргумента. Важно иметь возможность смотреть на функцию при чтении некоторого кода и сразу же видеть, на какие данные он воздействует, без необходимости смотреть на определение функции. Другими словами, все данные, с которыми работает функция, в идеале должны передаваться как значения. Наконец, и это серьезная проблема, проверка вашего имени слишком строгая. Он не потерпит дефисов, апострофов, акцентированных символов и т. Д. Я думаю, вы найдете, что либеральная проверка имени - лучшая политика. Например, некоторые соглашения о присвоении имен в культуре даже не имеют того, что мы считаем именами и фамилиями. Другая проблема: вместо того, чтобы использовать 'required' и 'option', используйте логическое значение для required. Если установлено значение TRUE, поле является обязательным.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...