2010-05-30 2 views
7
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-й func). Все это необходимо?Являются ли эти две функции излишними для дезинфекции?

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

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

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

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

+1

Из какой книги? – Gumbo

+0

Изучение PHP MySQL и Javascript – jpjp

+2

@jpjp: ... и я подумал, что О'Рейли просто для искушенных авторов. – Gumbo

ответ

5

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

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

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

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

+4

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

+0

@Dave Sherohman: Я как бы попытался выразить эту концепцию, но вы объяснили ее лучше. Я отредактирую в вашей формулировке. – Matchu

+0

А как насчет уязвимости в sql-инъекции? – rook

0

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

3

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

+1

Да, я думаю, я должен избавиться от strip_tags. Kinda pointless – jpjp

+1

Или назовите его перед htmlentities – stagas

10

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

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

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

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

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


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

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

И чтобы сделать его более увлекательным : Вы сохраняете это входное значение в объявлении atabase.

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

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

  • Для URI сегмента пути контекста, мы должны бежать (по крайней мере) все те символы, которые позволяют нам изменить этот контекст ; в этом случае / (оставить текущий сегмент пути), ? и # (оба из них оставляют контекст URI-пути). Для этого мы можем использовать rawurlencode.
  • Для Строка JavaScript контексте нам необходимо позаботиться о ", ' и \. Для этого мы можем использовать 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;. И не использование только одной из этих функций позволит нарушить контекст.

+0

Я думаю, что я просто буду придерживаться mysql_real_escape_string и подготовил инструкции для SQL-инъекций и htmlentities для xss. – jpjp

+0

@jpjp: Это хороший способ! И если вы используете кодировку символов, которая может кодировать Unicode (например, UTF-8), вы можете просто использовать 'htmlspecialchars' вместо' htmlentities'. – Gumbo

+1

Требуется ли mysql_real_escape_string для подготовленных операторов? – stagas

2

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

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

+0

Итак, после того, как я mysql_real_escape_string изменил переменную (скажем, $ name), было бы просто вставить в db подготовленные операторы? – jpjp

+2

@jpjp: Если вы используете подготовленные операторы, вам не нужно ничего делать со строкой, без mysql_real_escape_string, без какой-либо дезинфекции. Для более, Google PDO PHP. – TheMagician

2

Нет, это не слишком много, это уязвимость.

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

Go вперед проверить код:

$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 кодирует одинарные и двойные кавычки, убедитесь, что переменная вы печатаете также заключенная в кавычки, это делает невозможным «вырваться» и выполнить код.

+0

Ручная дезинфекция - корень всего зла. –

+0

Но '' 'будет' " 'после' htmlentities'. Причина, по которой ваш пример работает, заключается только в том, что вы используете '' 'вместо' '' в значении атрибута HTML и объявлении строки MySQL. И '' 'заменяется только на' htmlentities', используя стиль цитаты * ENT \ _QUOTES *: '$ var = htmlentities ($ var, ENT_QUOTES);' также исправить это. Операция MySQL приведет к 'select * from mysql.пользователя, где Host = '1 ' или 1 = 1/*' 'и пример HTML в' '. – Gumbo

+0

Нет, только mysql_real_escape_string() является * не лучшим, чтобы остановить SQL-инъекцию. Способ получения * абсолютной защиты - это использование параметризованных запросов, которые отправляют команды и данные в механизм базы данных по отдельным каналам, делая SQL-инъекцию * невозможной *. Не избегайте запросов. Не дезинфицируйте запросы. Используйте подготовленные заявления и заполнители. (Как, кстати, OP сказал, что он делает.) –

-1

Мне очень нравится концепция санитарии. Вы сообщаете 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) Для коротких и предсказуемых строк, которые должны соответствовать определенному стандарту (имя пользователя, адрес электронной почты, номер телефона и т. Д.), Вы можете: a) сделать подготовленные заявления; или b) регулярное выражение или другое подтверждение данных.

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

+1

-1: Не объединяйте и не интерполируйте данные, предоставленные пользователем, прямо в строки запроса. Период. Использовать параметризованные запросы (например, подготовленные заявления/заполнители) и SQL-инъекция ушли в прошлое. Обратите внимание, что ОП заявила: «Также для дезинфекции я использую подготовленные заявления для предотвращения инъекций sql». Поскольку он уже использует параметризованные запросы, ни один из этих методов полуразрядной дезинфекции не требуется, поэтому, пожалуйста, не представляйте их как подходящие средства защиты от SQL-инъекций. –

+0

@Dave. Я признаю, что увлекся, но я не согласен с вами в отношении бесполезности моих предложений. Подготовленные заявления - это способ предотвратить внедрение SQL-пакетов, да. Но нет, если позже будет использоваться другой интерфейс db, который может оставить всех, открывающих доступ к данным, либо доступными дырками, либо не осознавая этого, подтверждая, что загруженный текст в sql-инъекции был ранее сохранен. Кроме того, он ничего не дает для обеспечения целостности базы данных, а также для аннулирования атак xss и удаления html, который мог бы эффективно перерисовать весь сайт. –

+0

Кроме того, он ничего не дает для обеспечения целостности базы данных. Чтобы уточнить, вы, по-видимому, ограничены обозначением переменной как «idsb». Я не знаю себя, если это заставит тип. Однако этого недостаточно для проверки и целостности данных. У некоторых пользователей есть проблемы с блобами даже при настройке max_allowed_packet для компенсации. Некоторые пользователи находят mysqli buggy. И некоторые хосты строгие с db-соединениями и запросами, поэтому простой одноразовый запрос, распространяемый по двум вызовам db с использованием PS, иногда расточительный. Таким образом, PS все еще не является окончательным решением. –

Смежные вопросы