Веб-разработка

индекс
236,88

Не очередной XSS фильтр

Что есть Cross Site scripting? Об этом читайте на Википедии :)

Но знайте — во всем виноват браузер. Не важно: поддержиивает ли он HTML5 или до сих пор не понимает PNG прозрачность. Ну так как клиент всегда прав, то я расскажу как правильно фильтровать базар контент.


Немного о XSS


Философия XSS такова, что для внедрения вредоносного кода на страницу используется текст не «по правилам». Какие же они должны быть:
  • Наименование тега отделяется от аттрибутов только \r\t\n\s символами:
    <a href="http://habrahabr.ru">Click</a> <!-- Правильно -->
    <a\href="XSS">Click</a> <!-- Неправильно -->

  • HTML Entities, представленные в десятиричной/шестнадцатиричной формах должны быть переведены в свою привычную форму:
    &#106;&#97;&#118;&#97;&#115;&#99;&#114;&#105;&#112;&#116;
    javascript

  • Существует набор тегов, которых на странице пользователя быть не должно. Тут не стоит забывать и про HTML5, в котором есть теги (например audio, video), позволяющие злоумышленнику загружать код в браузер путем подмены ресурса на скриптлет.
  • Запрет на использование DOM событий.
  • Запрет на включение в аттрибут inline javascript или (внимание!) vbscript.
  • Запрет на использование в style таких IE-поделок как «expression» или CSS3 «behavior»

Это все из основного, более подробно о существующих видах атак можно почитать здесь

Как можно защититься?


Большинство решений по предотвращению XSS используют жесткую фильтрацию потенциально опасных конструкций.
Но давайте рассмотрим вот этот пример:
<a href=http://habrahabr.ru>javascript:alert("Hello");</a>

Уровень опасности этого кода равен нулю. Однако CodeIgniter вернет следующее (в других фреймворках не проверял, будет полезно почитать в комментах):
<a >[removed]alert("Hello");</a>

Так что воробей из пушки CodeIgniter убит.

Есть более гибкий фильтр


С недавнего времени я разрабатываю свой фреймворк Platcode. Но здесь я не пиарить его пришел, а рассказать о собственном XSS-фильтре.

Принцип работы прост — разбираем входную строку на теги/аттрибуты/значения, затем применяем фильтры на удаление опасных тегов и значений аттрибутов. Тем самым мы опускаем избыточную фильтрацию по всему тексту и делаем целенаправленные изменения в тегах/аттрибутах по отдельности. В этом случае вышеописанный пример сохранит свой первозданный вид. И клиент будет счастлив.

Из особеннностей фильтра:
  • удаление «опасных» тегов
  • удаление inline javascript/vbscript
  • удаление style аттрибута, содержащего expression, behavior
  • преобразование названий тегов/аттрибутов в lowercase
  • удаление пустых аттрибутов
  • автоматическое создание закрывающихся тегов
  • преобразование одинарных тегов вида <br> к <br />

Код, правда, документирован очень плохо, но функционал 100% работоспособный. Кому интересно поучавствовать в проекте или взломать XSS-фильтр, пишите в личку.

UPD.

Протестировать XSS-фильтр Да не сойдет на хостера хабрааффект :)

UPD2.

Благодаря хабрасообществу отлов и исправление багов идут ноздря в ноздрю.

Респект хабрапользователям: insaisisrecompilemefloppyformator, ICQ:32523553
+19
28 сентября 2009, 02:14
46

комментарии (61)

+4
remal #
Я бы при помощи Tidy приводил бы ввод к XML, а дальше можно при помощи того же самого XSLT прибивать лишнее.
+6
corristo #
0
Kakysha #
Пробовал Jevix & htmlpurifier. Остановился на jevix'e, который опказался гораздо понтянее и проще и легче (заметно легче). Алco присутствует полезная связка Jevix'a и Geshi(подсветка кода) + video парсера, и все это в одной библиотеки дял CI: www.coolweb.su/blog/7.html
0
eugeneorlov #
htmlpurifier
0
dienow #
Warning: Element '<style><a>' is not supported (for information on implementing this, see the support forums) in /home/ezyang/htmlpurifier.org/live/library/HTMLPurifier/HTMLDefinition.php on line 265
К тому же мне работать с white list не так удобно как с black list.
0
regeda #
Если
0
regeda #
если <style> еще можно понять, то что плохого сделал старый добрый <a> ???
0
dienow #
Видимо плохо ему стало именно от style, с «a» без «style» у него всё хорошо.
+1
eugeneorlov #
black list — зло, т.к. все возможные дыры предусмотреть невозможно.
0
dienow #
Да, постепенно прихожу к тому же выводу. Хоть blacklist и whitelist у меня в разы, обрезать редкий тэг меньшая беда чем пропустить вредоносный код. Честно говоря, до прочтения вот этого ha.ckers.org/xss.html я и не представлял что xss атаки бывают настолько разнообразны.
+1
egorinsk #
А вы можете написать 100%-ный black list?
0
dienow #
Не могу, согласен с Вами. Я просто знал о некоторых хитрых способах обойти защиту, но не знал что их так много =( Теперь уже склоняюсь к white list.
0
boston #
Старенький, но проверенный phpinputfilter
+2
tenshi #
-moz-binding
0
regeda #
Данная фича тоже фильтруется
+1
tenshi #
а сколько их ещё не фильтруется…
+3
tenshi #
> Кому интересно поучавствовать в проекте или взломать XSS-фильтр, пишите в личку.
создай страничку с песочницей…

0
LMaster #
dev.plakmag.ru/xss:
</textarea> < script> alert('xss');</script>
(удалите пробелы).
0
regeda #
Ну максимум, Вы украдете свои данные.
0
LMaster #
Почему? Контекстно загрузить страницу с передачей POST-параметра и последующим воровством cookies никто не отменял.
+2
regeda #
OK! Обновлено
0
recompileme #
вот такие ссылки проходят в фф
ой, не знаю пустит ли фльтр хабра))
XSS
–1
recompileme #
гыгыгы
1
+3
recompileme #
хабр не пропустил)
А ваш — пропустил вот такой xss

Вобщем не стило хаять кодеигнайтер. Его защиту я так и не смог пробить, а ваша свалилась через 10 минут
0
regeda #
Я CI не хаял, а просто показал один пример. Благодаря Вашему фидбеку данная уязвимость будет устранена ))
0
regeda #
Обновлено! Значения в аттрибутах @href @src пропускаются через «rawurldecode»
0
recompileme #
т.е. сразу выведите читсый javаscript вместо непонятных символов?
Библиотека для фильрации XSS в codeigniter совсем не зря заменяет javаscript на [removed] Совсем. Не зря. Вы слишком самоуверены мне кажется. Не разобравшись толком раскритиковали выбранный кодеигнайтером метод и предложили свой, не потрудившись даже прогнать его через топ 500 xss скриптов.
0
regeda #
если у Вас есть на руках Ваш топ 500, то милости прошу на обозрение.
А чистый javascript, конечно же, не пропускается ;)
0
recompileme #
0
regeda #
Этот ТОП использовался как отправная точка для написания фильтра, все примеры проверялись на корректное преобразование
0
egorinsk #
А разве такой способ работает в браузере? Это вообще уязвмость?
0
regeda #
Скорее всего нет…
Во всяком случае Opera 10 не преобразует %3C в < или %3A в двоеточие
+1
egorinsk #
Дык а смыл тогда блокировать? давайте теперь и русское слово «яваскрипт» банить :) Вот за этои не люблю эти фильтры — работают бестолково, видимо единтвенный нормальный способ — разрираьть текст по тегам/аттрибутам/виду ссылки и пересобирать заново.

0
regeda #
Если надо будет банить «яваскрипт», то будем банить
0
Isis #
0
recompileme #
знакомые всё ники)
+3
Isis #
Простите,
<img src='http://ya.ru/logo.gif'bo=o"onload="alert();>
0
regeda #
Спасибо за пример
0
regeda #
Обновлено! Теперь в unquoted значениях аттрибутов все двойные кавычки экранируются.
<img src='http://ya.ru/logo.gif' bo="o\"onload=\"alert();" />
+1
FloppyFormator #
Ещё вот такая штука прокатывает:

<img src="http://ya.ru/logo.png" style=color:red;"onload=alert('XSS!');a="1>
+1
FloppyFormator #
Адский парсер! Я имел в виду вот это: <img src="http://ya.ru/logo.png" style=color:red;"onload=alert('XSS!');a="1>
+2
FloppyFormator #
Ох ты ж ёканый бабайка, получите-ка лучше картинку:
0
pxx #
Вы не могли бы пояснить, благодаря чему этот код сработает?
Я в XSS не силен, поэтому мне он с виду кажется абсолютно безумным и не дееспособным.
0
regeda #
Как показала практика и примеры других участников, экранирование — не лучший способ, поэтому двойные кавычки в unquoted значения аттрибутов заменяются на "
0
regeda #
фу-ты, ну-ты на & quot;
+3
artyfarty #
ооо.
Я покажу вам страшную вещь — презентацию с конференции BlackHat.
Когда я её прочитал, я полчаса сидел в шоке.

Оригинальный линк лежит, поэтому перезалил к себе: artyfarty.ru/blackhat_xss.rar

Советую всем хабраюзерам ознакомится. Вообще, сиё творение достойно топика-ссылки или топика-перевода.
+1
artyfarty #
Спойлер:
(É=[Å=[],µ=!Å+Å][µ[È=-~-~++Å]+({}+Å) [Ç=!!Å+µ,ª=Ç[Å]+Ç[+!Å],Å]+ª])() [µ[Å]+µ[Å+Å]+Ç[È]+ª](Å)

($=[$=[]][(__=!$+$)[_=-~-~-~$]+({}+$)[_/_]+($$=($_=!''
+$)[_/_]+$_[+$])])()[__[_/_]+__[_+~$]+$_[_]+$$](_/_)

Это тоже xss-вектор. Я правда до конца не понял принципа именно этой техники, но там и других извращений мама мия.
0
egorinsk #
Это не вектор, это кусок кода на яваскрипте, отличающийся от нормального тем, что в нем не ипользуюстя симолы [a-z0-9], только и всего. Попробуйте этой фигней что нибудь взломать.
0
artyfarty #
Адресуйте это автору презентации. Как я написал, я сам не до конца понял, как это применить, но выглядит впечатляюще :)
+1
insa #
Сходу бага в обработке IE «expression», по мотивам onsec.ru/vuln?id=5
0
regeda #
Обновлено! IE «expression» фильтруется даже если каждый символ экранируется символом \ или C-подобным комментарием /*XSS*/:

style="onsec:e\x\p\re\s\s\i\o\n(alert('XSS'))"


или
style="onsec:e/*XSS*/x/*XSS*/p/*XSS*/re/*XSS*/s/*XSS*/s/*XSS*/i/*XSS*/o/*XSS*/n(alert('XSS'))"

+7
insa #
Остается только пожелать успехов в этом неравном бою с бесконечностью :)
0
Becoming_Insane #
Странно, никто не вспомнил про htmLawed, а ведь он, имхо, достаточно крутой соперник и джевиксу и саксу и инпутфильтру.

вывод сделан опытным путем, вставвляя дескрипшены айтемов с ебэя и смотря на то, что в итоге приходит.
надо было чтобы всё было один в один, тока без опасных элементов. (не все дескры подходили, т.к. в некоторых менюхи генерились динамически ЖС-ом. на такие забивали)
сначала юзали джевикс, но он подвел, потом сакс, подвел, вернули джевикс — и там карачун.
да и у джевикса рекурсивный вывод жрал много памяти при дереве > 20-и нодов, при этом пхп сначала умирал с ошибкой нестед левел 100 ричед
+1
artyfarty #
Мне стукнул в аську человек, не имеющий аккаунта тут (32523553), и попросил выложить ещё одну строку, обходящую фильтр:
<img src='o.gif'bo=o"onerror=alert();//>

Он очень желает присоединится к дискуссии и ищет инвайт. У меня, увы, инвайта нет.

Он какбы говорит нам: «экранизация там не играет роли. в прошлом рабочем варианте она помогла только потому что перед знаком равно возник слеш»
0
cdbrk #
Если пропускать html-тэги, то вероятность xss всегда будет существовать.
Почему бы не использовать bb-код?
0
regeda #
А если используется WYSIWYG редактор? То HTML нужно преобразовывать в bb-код, а потом обратно?
0
artyfarty #
Так делает IPB.
0
egorinsk #
В общем, по итогам обсуждения и четния ha.ckers.org, у меня такие мысли:

Фильтр автора — несовершенен, т.к. использует конечные автоматы (чтает по символу), что очень медленно, фильтрует по черным спискам (что также плохо, т.к. не предугадаешь все уязвимости).

Моя идея — надо делать одно из 2: 1) преобразовывать входные данные в дерево DOM, и проходить по нему белым списком, затем пересобирать уже валидный и безопасный HTML 2) чтобы побыстрее делать — парсить регулярками на теги/аттрибуты/текст и опять же, проходить белым списком, и пересобирать заново. Ключевое слово — пересобирать, чтобы обезвредить выходной код. В этом случае всякие уязвимости с незакрытими тегами, двойными скобками и прочими нарушениями синтаксиса просто превратятся в безвредный обычный текст.
0
regeda #
Идея с белым листом мне очень нравится, скорее всего буду развивать защиту в этом ключе.
Изначально алгоритм с конечным автоматом заложен для реализации как php extension, что будет крайне быстро.
Если по-Вашему итог в обсуждении и поставлен, то в развитии кода ставится «to be continued».
0
egorinsk #
Так объясните хоть, чем ваш способ, медленно ковыряться по одному символу, лучше идеи разрезать регуляркой код на куски и их перебирать, а потом склеить назад?
0
regeda #
1. разрезание и фильтрация тегов идет в одном цикле без повторных действий.
2. повторюсь, что метод с конечным автомат (ковырянием по одному символу) заложен для реализации как php extension

Только зарегистрированные пользователи могут оставлять комментарии. Войдите, пожалуйста.