При получении пользовательского ввода в формах я хочу определить, не содержат ли поля "имя пользователя" или "адрес" разметку, которая имеет особое значение в XML (RSS-каналах) или (X) HTML (если отображается).
Итак, какой из них является правильным способом определить, не введен ли введенный ввод каких-либо специальных символов в контексте HTML и XML?
if (mb_strpos($data, '<') === FALSE AND mb_strpos($data, '>') === FALSE)
или
if (htmlspecialchars($data, ENT_NOQUOTES, 'UTF-8') === $data)
или
if (preg_match("/[^\p{L}\-.']/u", $text)) // problem: also caches symbols
Я пропустил что-нибудь еще, например, последовательности байтов или другие сложные способы получить метки разметки вокруг таких вещей, как "javascript:"? Насколько мне известно, все атаки XSS и CSFR требуют <
или >
вокруг значений, чтобы заставить браузер выполнять код (ну, по крайней мере, из Internet Explorer 6 или новее в любом случае) - это правильно?
Я не ищу что-то, чтобы уменьшить или фильтровать вход. Я просто хочу найти последовательности опасных символов, когда они используются в контексте XML или HTML. (strip_tags()
является ужасно опасным. Как говорится в руководстве, он не проверяет неверный HTML.)
Update
Я думаю, мне нужно уточнить, что многие люди принимают этот вопрос за вопрос об основной безопасности посредством "экранирования" или "фильтрации" опасных символов. Это не тот вопрос, и большинство простых ответов в любом случае не решит эту проблему.
Обновление 2: Пример
- Пользователь отправляет ввод
-
if (mb_strpos($data, '<') === FALSE AND mb_strpos($data, '>') === FALSE)
- Я сохраняю его
Теперь, когда данные находятся в моем приложении, я делаю с ним две вещи: 1) отображение в формате HTML - или 2) отображение внутри элемента формата для редактирования.
Первый безопасен в контексте XML и HTML
<h2><?php print $input; ?></h2>'
<xml><item><?php print $input; ?></item></xml>
Вторая форма более опасна, но она все равно должна быть безопасной:
<input value="<?php print htmlspecialchars($input, ENT_QUOTES, 'UTF-8');?>">
Обновление 3: Рабочий код
Вы можете загрузить созданный мной gist и запустить код как текст или HTML-ответ, чтобы посмотреть, о чем я говорю. Эта простая проверка передает http://ha.ckers.org XSS Cheat Sheet, и я не могу найти ничего, что делает это. (Я игнорирую Internet Explorer 6 и ниже).
Я начал еще одну награду, чтобы наградить кого-то, кто может показать проблему с этим подходом или слабость в ее реализации.
Обновление 4: запрос DOM
Это DOM, который мы хотим защитить - так почему бы просто не спросить об этом? Ответ Тимура приведет к следующему:
function not_markup($string)
{
libxml_use_internal_errors(true);
if ($xml = simplexml_load_string("<root>$string</root>"))
{
return $xml->children()->count() === 0;
}
}
if (not_markup($_POST['title'])) ...