Эти две функции излишни для очистки? - PullRequest
7 голосов
/ 30 мая 2010
function sanitizeString($var)
{
    $var = stripslashes($var);
    $var = htmlentities($var);
    $var = strip_tags($var);
    return $var;
}

function sanitizeMySQL($var)
{
    $var = mysql_real_escape_string($var);
    $var = sanitizeString($var);
    return $var;
}

Я получил эти две функции из книги, и автор говорит, что, используя эти две функции, я могу быть в большей безопасности от XSS (первая функция) и SQL-инъекций (2-я функция). Все ли это необходимо?

Также для дезинфекции я использую подготовленные операторы для предотвращения инъекций sql.

Я бы использовал это так:

$variable = sanitizeString($_POST['user_input']);
$variable = sanitizeMySQL($_POST['user_input']);

EDIT: Избавьтесь от strip_tags для 1-й функции, потому что она ничего не делает. Будет ли достаточно использовать эти две функции, чтобы предотвратить большинство атак, и будет ли это нормально для публичного сайта?

Ответы [ 7 ]

10 голосов
/ 31 мая 2010

Если честно, я думаю, что автор этих функций либо не знает, что такое инъекции XSS и SQL, либо что именно делает используемая функция.

Просто назвать две странности:

  • Использование stripslashes после mysql_real_escape_string удаляет косые черты, добавленные mysql_real_escape_string.
  • htmlentities заменяет чата < и >, которые используются в strip_tags для идентификации тегов.

Более того: Как правило, функции, защищающие XSS против повторного использования, не подходят для защиты от SQL-инъекций и наоборот. Потому что каждый язык и контекст имеют свои специальные символы, о которых нужно позаботиться.

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


Редактировать Вот некоторый (возможно, странный) пример: представьте, что вы позволяете своим пользователям вводить какое-то значение, которое следует использовать в качестве сегмента пути в URI, который вы используете в некотором коде JavaScript в onclick значение атрибута. Итак, языковой контекст выглядит так:

  • Значение атрибута HTML
    • строка JavaScript
      • Сегмент пути URI

И чтобы было веселее: вы сохраняете это входное значение в базе данных.

Теперь, чтобы правильно сохранить это входное значение в вашей базе данных, вам просто нужно использовать правильную кодировку для контекста, который вы собираетесь вставить, это значение в язык вашей базы данных (т.е. SQL); остальное не имеет значения (пока). Поскольку вы хотите вставить его в объявление строки SQL, контекстные специальные символы - это символы, которые позволяют вам изменить этот контекст. Что касается строковых объявлений, то это (особенно) символы ", ' и \, которые необходимо экранировать. Но, как уже говорилось, подготовленные заявления делают все, что работает для вас, поэтому используйте их.

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

  • Для контекста URI-сегмента нам нужно экранировать (как минимум) все те символы, которые позволяют нам изменить этот контекст; в этом случае / (оставить текущий сегмент пути), ? и # (оба оставить контекст пути URI). Для этого мы можем использовать rawurlencode.
  • Для контекста JavaScript string нам нужно позаботиться о ", ' и \. Для этого мы можем использовать json_encode (если доступно).
  • Для значения атрибута HTML нам нужно позаботиться о &, ", ' и <. Для этого мы можем использовать htmlspecialchars.

Теперь все вместе:

'… onclick="'.htmlspecialchars('window.open("http://example.com/'.json_encode(rawurlencode($row['user-input'])).'")').'" …'

Теперь, если $row['user-input'] равно "bar/baz", вывод:

… onclick="window.open(&quot;http://example.com/&quot;%22bar%2Fbaz%22&quot;&quot;)"

Но использование всех этих функций в этих условиях не является излишним. Потому что, хотя контексты могут иметь похожие специальные символы, они имеют разные escape-последовательности. URI имеет так называемую кодировку процентов, JavaScript имеет escape-последовательности, такие как \", а HTML имеет ссылки на символы, такие как &quot;. И не использование только одной из этих функций позволит нарушить контекст.

5 голосов
/ 30 мая 2010

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

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

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

Кроме того, обратите внимание, что strip_tags в вашей первой функции, скорее всего, не будет действовать, если все < и > станут &lt; и &gt;.

3 голосов
/ 30 мая 2010

Вы делаете htmlentities (который превращает все > в &gt;), а затем вызываете strip_tags, что на данный момент не принесет ничего большего, поскольку - это без тегов.

2 голосов
/ 31 мая 2010

Нет, это не перебор, это уязвимость.

Этот код полностью уязвим для SQL-инъекций. Вы делаете mysql_real_escape_string (), а затем вы делаете stripslashes (). Таким образом, " станет \" после mysql_real_escape_string (), а затем вернется к " после stripslashes (). Одна только mysql_real_escape_string () лучше всего останавливает внедрение SQL. Библиотеки параметризованных запросов, такие как PDO и ADODB, используют ее, а параметризованные запросы позволяют очень просто полностью остановить внедрение SQL.

Давай проверь свой код:

$variable = sanitizeString($_POST['user_input']);
$variable = sanitizeMySQL($_POST['user_input']);
mysql_query("select * from mysql.user where Host='".$variable."'");

Что если:

$_POST['user_input'] = 1' or 1=1 /*

Исправленный:

mysql_query("select * from mysql.user where Host='".mysql_real_escape_string($variable)."'");

Этот код также уязвим для некоторых типов XSS:

$variable = sanitizeString($_POST['user_input']);
$variable = sanitizeMySQL($_POST['user_input']);
print("<body background='http://localhost/image.php?".$variable."' >");

Что если:

$_POST['user_input']="' onload=alert(/xss/)";

исправлено:

$variable=htmlspecialchars($variable,ENT_QUOTES);
print("<body background='http://localhost/image.php?".$variable."' >");

htmlspeicalchars кодирует одинарные и двойные кавычки, убедитесь, что печатаемая вами переменная также заключена в кавычки, что делает невозможным «разбить» и выполнить код.

2 голосов
/ 31 мая 2010

Если вы используете подготовленные операторы и заполнители SQL и никогда не интерполируете пользовательский ввод непосредственно в строки SQL, вы можете полностью пропустить санацию SQL.

При использовании заполнителей структура оператора SQL (SELECT foo, bar, baz FROM my_table WHERE id = ?) отправляется в механизм базы данных отдельно от значений данных, которые (в конечном итоге) связаны с заполнителями. Это означает, что, исключая серьезные ошибки в ядре базы данных, абсолютно не может неверно интерпретировать значения данных как инструкции SQL, поэтому это обеспечивает полную защиту от атак внедрения SQL без необходимости манипулирования данными для хранения.

0 голосов
/ 01 июня 2010

Интересно о концепции санации. Вы говорите Mysql делать именно то, что вы хотите: выполнить оператор запроса, частично созданный пользователем веб-сайта. Вы уже строите предложение динамически, используя пользовательский ввод - объединяя строки с данными, предоставленными пользователем. Вы получаете то, что просите.

В любом случае, вот еще несколько методов очистки ...

1) Для числовых значений всегда приводите вручную, по крайней мере, где-то до или во время создания строки запроса: "SELECT field1 FROM tblTest WHERE (id =". (Int) $ val. ")";

2) Для дат сначала преобразуйте переменную в метку времени Unix. Затем используйте функцию Mysql FROM_UNIXTIME (), чтобы преобразовать ее обратно в дату. "SELECT field1 FROM tblTest WHERE (date_field> = FROM_UNIXTIME (". Strtotime ($ val). ")";. Это на самом деле иногда необходимо в любом случае, чтобы иметь дело с тем, как Mysql интерпретирует и сохраняет даты, отличные от уровней сценария или ОС.

3) Для коротких и предсказуемых строк, которые должны соответствовать определенному стандарту (имя пользователя, адрес электронной почты, номер телефона и т. Д.), Вы можете: а) сделать подготовленные заявления; или b) регулярное выражение или другая проверка данных.

4) Для строк, которые не будут соответствовать какому-либо реальному стандарту и которые могут иметь или не иметь пре- или двойной экранированный и исполняемый код повсюду (текст, заметки, разметка вики, ссылки и т. Д.), Вы можете а) делать подготовленные заявления; или b) сохранить и преобразовать из двоичной / блоб-формы - преобразование каждого символа в двоичное, шестнадцатеричное или десятичное представление перед передачей значения в строку запроса и обратное преобразование при извлечении. Таким образом, вы можете сосредоточиться больше на проверке HTML, когда вы выплевываете сохраненное значение обратно.

0 голосов
/ 30 мая 2010

Ну, если вы не хотите изобретать велосипед, вы можете использовать HTMLPurifier . Это позволяет вам точно решить, что вы хотите, а что нет, и предотвращает атаки XSS и тому подобное

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