Очистка ввода в php


Я знаю, что sql-инъекции обсуждались много-много раз здесь, в stackoverflow.

Каковы недостатки использования этого метода

foreach($_POST as &$value)
    $value = mysql_real_escape_string($value);

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

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

Author: Ragnar123, 2011-08-21

7 answers

Основным недостатком использования этого кода является тот факт, что вы изменяете данные в массиве POST. Это может повлиять на операции с массивом СООБЩЕНИЙ позже (например, вывод на экран). Это также может привести к путанице, если вы работаете с другими программистами, где они могли бы разумно ожидать, что массив СООБЩЕНИЙ останется неизменным. По предыдущей причине это также может затруднить обслуживание кода. Любой, кто работает над кодом, должен знать, что вы изменили СООБЩЕНИЕ массив.

Мое предложение, если вы настроены на использование mysql_real_escape_string вместо параметризованных запросов, состоит в том, чтобы убедиться, что вы используете его в сочетании с sprintf и правильным спецификатором типа, например:

$query = sprintf("INSERT INTO purchases (amount, num_items, prod_descrip) 
                    VALUES (%f, %d, '%s')",
                    mysql_real_escape_string($_POST['amount'])
                    mysql_real_escape_string($_POST['num_items'])
                    mysql_real_escape_string($_POST['prod_descrip']));

Обратите внимание, что %f применяется к значениям с плавающей точкой, %d - к целым числам, а %s - к строковым значениям. Также обратите внимание, что я напрямую использую данные $_POST в строке запроса без какой-либо проверки, чего я бы не делал на практике (просто здесь для простоты).

 6
Author: A Jolly Geek, 2011-08-21 13:58:49

Любые данные следует экранировать не во время их сбора, а во время их использования, потому что вы можете использовать одни и те же данные в разных контекстах (запрос MySQL, шаблон preg, вывод HTML), и каждый контекст нуждается в другом экранировании. Более того, если вы таким образом удаляете данные, что вы делаете с другими источниками данных, допустим, вы считываете значение из файла или удаленной службы XML? Легко забыть, чтобы избежать этого, и легко забыть, какая ценность была ускользнута, а какая была нет, либо оставляя ваше приложение уязвимым, либо заканчивая двойным побегом. Как указал @genesis φ, описанный выше метод также должен быть рекурсивным для обработки массивов. И вам либо нужно использовать кавычки вокруг каждого значения в запросе, включая числа, либо вы уязвимы для атак sql-инъекций в этих параметрах.

 4
Author: Maxim Krizhanovsky, 2011-08-21 12:38:44

Этот подход имеет смысл только в том случае, если вы хотите, чтобы каждая отдельная переменная POST была отформатирована соответствующим образом для запроса MySQL.

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

 3
Author: Oliver Charlesworth, 2011-08-21 10:53:43

Я бы не стал использовать это. Бывают случаи, когда вам нужен только intval или вы передаете массив POST, что приведет к ошибке здесь. Вы можете упростить написание mysql_real_escape_string() каждый раз с помощью своей собственной функции

function mres($what){
    return mysql_real_escape_string($what);
}

И используя его

$query = '
    select column 
    from table 
    where column2 = "'.mres($_POST['var']).'"';
 2
Author: genesis, 2011-08-21 11:38:02

Не рекомендуется избегать публикации/ПОЛУЧЕНИЯ данных до их обработки. Обычно данные должны быть экранированы при создании запроса. Например:

$query = '
    select column_name 
    from table_name 
    where column_name = "'. mysql_real_escape_string($_POST['var_name']) .'"
';
 1
Author: Karolis, 2011-08-21 11:16:15

Для повышения эффективности я бы рекомендовал что-то вроде этого

$dbArr = array( 'key1','key2',...); //make these keys correspond with the POST vars you want in the db

foreach($dbArr as $goodCol){

    $sanitized[$goodCol] = mysql_real_escape_string($_POST[$goodCol]);

}
 0
Author: Dave Lasley, 2011-08-21 10:59:11

Если вам нравится регулярное выражение и вы хотите явно контролировать ввод, попробуйте это.

function match_implode($filter,$val,$cut=255){
    $m=array();
    if(!is_string($val)){
        return false;
    }
    preg_match_all($filter,$val,$m);
    if(!empty($m[0])){
        return substr(implode($m[0]),0,$cut);
    }
    return false;
}
//Only Alpha-numeric with a max-length of 20 chars.
echo match_implode("{[A-Za-z0-9]}",$_POST["alpha"],20);

//Practical use
if($user_id=match_implode("{[0-9]}",$_POST["id"])){
    mysql_query("UPDATE user SET last_login=UNIX_TIMESTAMP() WHERE user_id=$user_id");
}

//If you need to parse and escape email :)
if($email=match_implode("{^[a-z0-9\å\ä\ö._-]+@[a-z0-9\å\ä\ö.-]+\.[a-z]{2,6}$}i",$_POST["email"])){
    mysql_query("UPDATE user SET last_login=UNIX_TIMESTAMP() WHERE email='$email'");
}
 0
Author: Gustav, 2011-08-21 13:12:12