Дезинфекция/экранирование пользовательского ввода и вывода

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

Хорошо, вот оно. Если у меня есть PHP-скрипт, и я GET ввожу данные пользователей и SELECT из базы данных mySQL, будет ли это иметь значение/представлять ли какую-либо угрозу безопасности, если я не избежал < и > с помощью htmlspecialchars, htmlentities или strip_tags и поэтому разрешено выбирать/искать HTML-теги в базе данных? Поскольку ввод уже очищается с помощью trim(), mysql_real_escape_string и addcslashes (\%_).

Проблема с использованием htmlspecialchars заключается в том, что он экранирует амперсанд (&), который должен разрешать пользовательский ввод (полагаю, то же самое относится и к htmlentities?). При использовании strip_tags что-то вроде "John" приводит к тому, что PHP-скрипт выбирает и отображает результаты для John, чего он не должен делать.

Вот мой PHP-код для очистки ввода перед выбором из базы данных:

if(isset($_GET['query'])) {
  if(strlen(trim($_GET['query'])) >= 3) {
      $search = mysql_real_escape_string(addcslashes(trim($_GET['search']), '\%_'));
      $sql = "SELECT name, age, address WHERE name LIKE '%".$search."%'";
      [...]
  }
}

И вот мой вывод для отображения результатов «x соответствует y».:

echo htmlspecialchars(strip_tags($_GET['search']), ENT_QUOTES, 'UTF-8')." matched y results.";

person AnonymousJ    schedule 23.04.2013    source источник
comment
дезинфекция/экранирование должны выполняться для вашей целевой среды. html не может «влиять» на sql, поэтому безопасно оставить его неэкранированным в БД. на самом деле, лучше НЕ сбегать, пока вы не извлечете его и не попытаетесь отобразить в контексте браузера. это избавляет вас от необходимости экранировать, если вы действительно что-то ищете, и устраняет возможность двойного экранирования, например. &amp;amp;   -  person Marc B    schedule 23.04.2013
comment
Хорошо, спасибо. Итак, то, что я делаю, кажется достаточно правильным, да?   -  person AnonymousJ    schedule 23.04.2013
comment
нет. вы устаревшие функции mysql_*(). переключитесь на mysqli или PDO. и удалите вызов addcslashes(). Это необязательно и просто добавляет еще один уровень бессмысленного экранирования данных в БД. mysql_real_escape_string — это единственное, что вам нужно для безопасного использования данных формы в запросе.   -  person Marc B    schedule 23.04.2013
comment
Я знаю, что использую устаревшую функцию mysql_*(). Как я уже сказал @jball037, мне неоднократно предлагали это. Но я просто хотел знать, поможет ли то, что я упомянул выше. Кстати, addcslashes предназначен для защиты моего PHP-скрипта от отображения всего из базы данных, поскольку mysql_real_escape_string (насколько я понял) не экранирует подстановочные знаки, такие как % и _. И причина, по которой я добавил `` туда, заключается в том, что поиск John\'s будет искать в базе данных John's, что здесь не предусмотрено.   -  person AnonymousJ    schedule 23.04.2013
comment
вы ожидаете, что ваши пользователи будут вводить John\'s в поле поиска? Это никогда не взлетит. Вы позволяете им вводить все, что они хотят, а затем используете соответствующее экранирование, чтобы БЕЗОПАСНО получить эти данные в запросе. помните: mysql на самом деле не СОХРАНЯЕТ обратную косую черту в тексте. они удаляются как часть этапа разбора запроса. Если у вас есть INSERT ... VALUES ('John\'s'), то John's - это то, что на самом деле сохраняется в БД, а не John\'s.   -  person Marc B    schedule 23.04.2013
comment
Я не ожидаю их, но я не могу позволить своим сомнениям разрушить это для меня. Я понимаю, о чем вы говорите: я должен разрешить своим пользователям вводить <b>John's</b> или John\'s и т. д., удалив теги HTML и разрешив обратную косую черту, а затем отобразить результаты из базы данных, как если бы они искали John's. Но мой способ сделать это (отображение ошибки о том, что их поиск не дал никаких результатов) неверен?   -  person AnonymousJ    schedule 23.04.2013


Ответы (2)


Хороший способ сделать это — использовать MySQLi, он использует подготовленные операторы, которые по существу избегают всего для вас на бэкэнде и предлагают надежную защиту от SQL-инъекций. Не экранировать данные GET так же опасно, как и не экранировать любой другой ввод.

person jball037    schedule 23.04.2013
comment
Спасибо, что указали мне на функцию MySQLi. Мне его предлагали несколько раз, и я прочитаю его достаточно скоро. Но я полагаю, что переход от MySQL к MySQLi (или ради этого PDO) не может быть выполнен за одну ночь, верно? - person AnonymousJ; 23.04.2013
comment
PDO имеет некоторые преимущества по сравнению с mysqli, особенно именованные заполнители. Это можно сделать за одну ночь, если у вас не так много кода базы данных для адаптации. Изучение PDO занимает всего около получаса. - person tadman; 23.04.2013
comment
Зависит от того, сколько кода (и запросов MySQL) у вас есть. Вам придется переключить все ваши текущие запросы MySQL в формат MySQLi, но в остальном не так много накладных расходов. Я не могу говорить с PDO, так как ничего о нем не знаю :) - person jball037; 23.04.2013
comment
Что ж, мой PHP-скрипт довольно прост. Он имеет форму ввода, где пользователь выполняет поиск, и результаты этого поиска затем отображаются пользователю. В моем посте упоминается только запрос MySQL. Я думаю, это было бы довольно легко? Я обязательно рассмотрю это. :-) - person AnonymousJ; 23.04.2013

Здесь есть две разные проблемы, которые вы определили.

Данные пользователя в операторах SQL

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

Данные пользователя в документе HTML

Когда вы визуализируете страницу, содержащую контент, отправленный пользователем, вам необходимо экранировать его, чтобы пользователь не мог ввести произвольные теги HTML или элементы сценария. Это позволяет избежать проблем XSS и означает, что такие символы, как & и <, не интерпретируются неправильно. Пользовательские данные «x ‹ y» не приведут к поломке вашей страницы.

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

person tadman    schedule 23.04.2013