2011-04-26 2 views
42

Есть известная XSS или другое нападение, что делает его мимоЯвляется ли strip_tags() уязвимым для скриптовых атак?

$content = "some HTML code"; 
$content = strip_tags($content); 

echo $content; 

?

manual имеет предупреждение:

Эта функция не изменяют атрибуты тегов, которые вы позволяете с помощью allowable_tags, в том числе стиля и OnMouseOver атрибутов, которые вредный пользователь может злоупотреблять при размещении текста, который будет показаны другим пользователям.

, но это связано только с параметром allowable_tags.

Не допускается набор тегов, является ли strip_tags() уязвимым для любой атаки?

Chris Shiflett, кажется, говорят, что это безопасно:

Используйте Зрелые решения

Когда это возможно, использовать зрелые, существующие решения, вместо того, чтобы пытаться создать свой собственный. Такие функции, как strip_tags() и htmlentities(), являются хорошим выбором.

Это все верно? Если возможно, укажите источники.

Я знаю об очистителе HTML, htmlspecialchars() и т. Д. Я не ищет лучший метод для дезинфекции HTML. Я просто хочу знать об этой конкретной проблеме. Это теоретический вопрос, который возник here.

Ссылка: strip_tags() implementation in the PHP source code

+1

Ну, никаких аргументов, он не выдает _all_ теги, поэтому я не вижу, как может быть какой-либо эксплойт. Самое худшее, что произойдет, - это кто-то, кто кормит вас недействительной разметкой (без закрывающих тегов), но этот худший случай просто означает, что 'strip_tags' выделяет намного больше текста. – Damon

+0

@ Gordon благодарит меня, но я имею в виду целый кусок данных HTML, поэтому никаких инъецированных имен файлов и т. Д. (Что, если я правильно понимаю, это то, что обсуждается в форуме). Насколько я понимаю, поток Не доказывайте уязвимость в strip_tags(), но продолжайте рекомендовать htmlspecialchars() - это то, что я обычно делаю, но я хочу знать, действительно ли это необходимо * –

+0

Вы можете проверить способ работы 'strip_tags' глядя на [реализацию] (http://lxr.php.net/opengrok/xref/PHP_5_3/ext/standard/string.c#php_strip_tags_ex). – Lekensteyn

ответ

42

Как следует из его названия, strip_tags должен удалить все теги HTML. Единственный способ доказать это - проанализировать исходный код. Следующий анализ относится к вызову strip_tags('...'), без второго аргумента для белых списков.

Прежде всего, некоторая теория о тегах HTML: тег начинается с <, за которым следуют символы без пробелов. Если эта строка начинается с ?, это should not be parsed. Если эта строка начинается с !--, это считается комментарием, и следующий текст не должен анализироваться. Комментарий заканчивается -->, внутри такого комментария допускаются символы, такие как < и >. Атрибуты могут встречаться в тегах, их значения могут быть дополнительно окружены символом кавычки (' или "). Если такая цитата существует, она должна быть закрыта, иначе, если встречается >, тег не закрывается.

Код <a href="example>xxx</a><a href="second">text</a> интерпретируется в Firefox как:

<a href="http://example.com%3Exxx%3C/a%3E%3Ca%20href=" second"="">text</a> 

PHP-функция strip_tags упоминается в line 4036 of ext/standard/string.c. Эта функция вызывает internal function php_strip_tags_ex.

Существуют два буфера, один для вывода, другой для «внутри HTML-тегов». Счетчик с именем depth содержит количество угловых скобок (<).
Переменная in_q содержит символ цитаты (' или "), если таковой имеется, и 0 в противном случае. Последний символ хранится в переменной lc.

Функции содержат пять состояний, три упомянутые в описании выше функции. На основе этой информации и функции тела, следующие состояния могут быть получены:

  • Состояние 0 является состояние выхода (не в любом теге)
  • Государство 1 означает, что мы находимся внутри нормального HTML тег (тег буфер содержит <)
  • государство 2 означает, что мы внутри PHP тега
  • State 3: мы пришли из выходного состояния и столкнулись с < и ! символы (буфер тег содержит <!)
  • государства 4: внутри HTML комментарий

Нам нужно просто быть осторожным, чтобы ни один тег не был вставлен. То есть, <, за которым следует символ без пробелов. Line 4326 проверяет дела о < с характером, который описан ниже:

  • Если внутри котировки (например <a href="inside quotes">), то < символ игнорируется (удаляется из выходного сигнала).
  • Если следующий символ является символом пробела, в выходной буфер добавляется <.
  • если вне HTML тега, состояние становится 1 («внутри HTML-тега») и последний символ lc установлен в <
  • В противном случае, если внутри в HTML-тег, счетчик с именем depth увеличивается и характер игнорируются.

Если > выполняется в то время как тег открыт (state == 1) in_q становится 0 («не в цитате») и state становится 0 («не в теге»). Буфер тега отбрасывается.

Проверка атрибутов (для таких символов, как ' и ") выполняется в буфере тега, который отбрасывается. Таким образом, вывод:

strip_tags без ярлыка тега безопасен для включения внешних тегов, без тегов.

Под «наружными тегами», я имею в виду не в тегах, как в <a href="in tag">outside tag</a>. Текст может содержать < и >, хотя, как и в >< a>>. Результат недействителен HTML, хотя <, > и & еще нужно избежать, особенно &. Это можно сделать с помощью htmlspecialchars().

Описание для strip_tags без белого списка аргументов будет:

Гарантирует, что ни один HTML тег не существует в возвращаемой строке.

+4

Итак ... tldr; - да, 'strip_tags()' безопасен? – rinogo

2

Газа теги совершенно безопасно - если все, что вы делаете вывод текста в HTML тела.

Не обязательно безопасно помещать его в атрибуты mysql или url.

9

Я не могу предсказать будущие эксплойты, тем более, что я не смотрел исходный код PHP для этого. Тем не менее, в прошлом были эксплойты из-за того, что браузеры принимали, казалось бы, недопустимые теги (например, <s\0cript>). Поэтому вполне возможно, что в будущем кто-то сможет использовать нечетное поведение браузера.

Это в стороне, посылая вывод непосредственно в браузере, как полный блок HTML никогда не должно быть небезопасно:

echo '<div>'.strip_tags($foo).'</div>' 

Однако это не безопасно:

echo '<input value="'.strip_tags($foo).'" />'; 

потому, что можно было бы легко завершите цитату через " и вставьте обработчик сценария.

Я думаю, что гораздо безопаснее всегда преобразовывать бездомные < в &lt; (и то же с кавычками).

2

Согласно this online tool, эта строка будет «отлично» экранирована, но результат - другой злой!

<<a>script>alert('ciao');<</a>/script> 

В строке «настоящие» метки <a> и </a>, так как < и только script> не теги.

Надеюсь, я ошибаюсь или что это просто из-за старой версии PHP, но лучше проверить свою среду.

+0

'var_dump (strip_tags (" <) script> alert ('ciao'); </script> "));' => '" alert ('ciao'); "' в PHP 7.1.2. Кажется, он удаляет все после того, как встречается '<', пока не встретится '>'. – luckydonald

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