Я думаю, что вы путаете две проблемы безопасности: инъекция SQL и межсайтовый скриптинг (XSS).
Веб-сайт уязвим для SQL-инъекций, когда в SQL-запросе, отправляемом в базу данных SQL, используется неправильно очищенный пользовательский ввод. Этот код, например, представляет уязвимость SQL-инъекции:
mysql_query("INSERT INTO postmessages (postmessage) VALUES ('" . $_POST['postmessage'] . "')");
Эту проблему легко исправить, экранируя пользовательский ввод с помощью такой функции, как mysql_real_escape_string
:
mysql_query("INSERT INTO postmessages (postmessage) VALUES ('" . mysql_real_escape_string($_POST['postmessage']) . "')");
Это все, что вам нужно сделать, но сложная часть состоит в том, чтобы не забывать делать это для каждого элемента пользовательского ввода, который используется в операторе SQL.
Веб-сайт уязвим для межсайтового скриптинга, когда пользовательский ввод используется в HTML, отправляемом клиенту. Этот код, например, вводит уязвимость XSS:
echo "<div class='postmessage'>" . $_POST['postmessage'] . "</div>";
Уязвимость XSS устраняется путем экранирования пользовательского ввода с помощью такой функции, как htmlspecialchars
:
echo "<div class='postmessage'>" . htmlspecialchars($_POST['postmessage']) . "</div>";
Опять же, это легко сделать, но легко забыть. .
Обычно пользовательский ввод, который помещается в базу данных для использования при отправке обратно HTML в более позднее время, сохраняется без изменений. То есть используется только mysql_real_escape_string
.Однако вы можете экранировать пользовательский ввод, чтобы предотвратить XSS, а затем экранировать безопасную для XSS строку, чтобы предотвратить внедрение SQL:
mysql_query("INSERT INTO postmessages (postmessage) VALUES ('" . mysql_real_escape_string(htmlspecialchars($_POST['postmessage'])) . "')");
Преимущество в том, что вам не нужно помнить об экранировании значений из базы данных с помощью htmlspecialchars
, прежде чем записывать их в HTML. Недостатком является то, что некоторые значения могут нуждаться в экранировании с помощью разных функций. Например, имя пользователя, вероятно, будет экранировано htmlspecialchars
, но «постсообщение» может разрешать BBcode, Markdown или подмножество HTML. Если вы экранировали все входные данные, чтобы предотвратить XSS, вам нужно будет отменить экранирование значений из базы данных, например, htmlspecialchars_decode
.
Одна из проблем заключается в том, что отмена экранирования экранированной строки не всегда возвращает исходную строку (unescape(escape($orig))
не обязательно совпадает с $orig
). Даже с htmlspecialchars
и htmlspecialchars_decode
использование другого стиля кавычек вызовет эту проблему. Другой пример: если используется strip_tags
, информация удаляется безвозвратно; вы не сможете отменить strip_tags
. Таким образом, многие разработчики предпочитают использовать mysql_real_escape_string
только для сохранения значений в базе данных и htmlspecialchars
(или что-то еще) для подготовки строки из базы данных для использования в HTML.
mysql_real_escape_string()
— единственный метод, который вам здесь понадобится.
Не следует выполнять ни htmlentities()
, ни urlencode()
перед вставкой данных в базу данных. Эти методы обычно представляют собой код, выполняемый во время рендеринга представления, которое вы предлагаете своим пользователям.
Лучшим способом избежать SQL-инъекций является использование подготовленных операторов.
Ресурсы:
По той же теме:
Вы также должны использовать "
в том месте, где вы вставляете свой код.
Например, если вы сделаете
$_POST['userid'] = mysql_real_escape_string($_POST['userid']);
mysql_query('SELECT * FROM user WHERE userid = '. $_POST['userid']);
mysql_real_escape_string 'ничего не помогает. Это потому, что $_POST['userid'] не окружен '.
Поэтому вместо этого вы должны использовать
$_POST['userid'] = mysql_real_escape_string($_POST['userid']);
mysql_query('SELET * FROM user WHERE userid = \''. $_POST['userid'] .'\'');
.
Таким образом, использование mysql_real_escape_string для ваших переменных не означает автоматически, что они безопасны в любом случае.
Другим подходом может быть использование подготовленных операторов.
Да, но есть причина не использовать mysql_real_escape_string(). Во-первых, больно печатать. Во-вторых, вы должны не забывать использовать его каждый раз. В-третьих, это делает ваш код уродливым. В-четвертых, вы должны не забывать цитировать свои строки. В-пятых, таким образом сложнее вставлять BLOB-объекты в БД.
Изучение PDO сделает вашу жизнь лучше в долгосрочной перспективе. Учиться сложнее, чем просто использовать mysql_real_escape_string(), но долгосрочные преимущества перевешивают неудобства кривой обучения.