Являются ли эти две функции излишними для дезинфекции?

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 для первой функции, потому что она ничего не делает. Будет ли использование этих двух функций достаточным для предотвращения большинства атак и будет хорошо для публичного сайта?

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

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

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

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

Честно говоря, я думаю, что автор этой функции не знает, что такое 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 нам нужно позаботиться о " , ' и « \ . Мы можем использовать 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; . И не использование только одной из этих функций позволит разбить контекст.

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

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

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

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

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

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

Я задаюсь вопросом о концепции санитарии. Вы сообщаете 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, когда вы вернете сохраненное значение обратно.