Welcome to php club

PHP FAQ from PHPclub.ru: XSS/Prevention ...

Начало | Каталог | Изменения | НовыеКомментарии | Вам запрещён доступПользователи | Вам запрещён доступРегистрация | Вход:  Пароль:  

Предупреждение XSS-атак
Источник: XSS Prevention

Введение


Кросс-сайтовый скриптинг (Cross Site Scripting), так же известный как XSS, является чрезвычайно важной проблемой вэб-приложений, о чём дискутировали в листе рассылки phpsec. О том, как мы с некоторых пор пытаемся предотвратить XSS в нашем приложении BxCMS, я писал в блогенебольшое обновление) и использовал в онлайновой тестовой страничке. Довольно немало людей тестировало различные эксплойты и я продолжаю улучшать наш скрипт.


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

Что такое кросс-сайтовый скриптинг (он же XSS)?


Я слишком ленив, чтобы описывать что-то, поэтому смотрите статью Криса Шифлетта для ознакомления и введения в XSS.

О нашем скрипте


Мы решили разрешить использование некоторых HTML-тэгов в нашей гостевой, но разрешить всё – не лучшая идея. Итак, мы начали с простого регулярного выражения для наиболее общих случаев. Как и со всеми случаями входных данных в XML-стиле, вскоре мы получили законченный комплекс. Он далеко не идеален, но позволяет предотвратить большинство случаев (по крайней мере, из известных мне). Он иногда очищает слишком много, но если кто-нибудь попытается ввести код эксплойта, то, что удаляется не только плохой код, ИМХО, не имеет значения. Он ничего не удаляет, если ввод правильный.


I also recommend applying tidy before and maybe even after the script. tidy itselfs fixes some badly written HTML, which makes the regexes easier. I don't rely on tidy in the script, but I nevertheless recommend it.


The script also does not prevent “CSS Hacking”, meaning you can quite simply change the layout of a page with like background-color or whatever. This is not dangerous, just annoying.


If you don't want HTML in the input at all, there are much easier ways to prevent that, than this approach, just use some regular PHP functions like strip_tags and htmlentities.

Другие решения


* http://pixel-apes.com/safehtml – Решение на базе htmlsax.


Очень хорошее решение. Чистит больше, чем мой вариант и, благодаря htmlsax, может, например, намного лучше проверять отдельные значения аттрибутов и не зависит от регулярных выражений. Кроме того, этот вариант не медленнее, чем мое решение.


* http://cvs.horde.org/co.php/framework/MIME/MIME/Viewer/html.php – встроен в Horde


Против этих решений аргументов нет. Они намного старше, и, следовательно, лучше оттестированны и более безопасны, чем мое решение. Когда я первый раз реализовывал свое решение, я еще не знал о существовании этих двух. Теперь я знаю, и, наверное, не стал бы писать свой вариант. Мне любопытно, что люди найдут в моем решении и как его может улучшить.

Скрипт по частям


Теперь я попытаюсь разобрать каждое регулярное выражение в отдельности и объяснить, что оно пытается предотвратить.

Entities in input


A very common approach to circumvent XSS-cleaners is to use entities instead of plaintext, therefore the first thing we do is to remove does entities with their UTF-8 equivalent (we assume, the input is utf-8 here)


$string = html_entity_decode($string, ENT_COMPAT, “UTF-8”);


Before doing that, there's one entity style, which html_entitiy_decode doesn't catch. An entity can have a white space before the closing ; (at least browsers do support). Something like


ä
;


is perfectly treated as an ä. We do remove this with:


$string = preg_replace('#(&\#*\w+)[\x00-\x20]+;#U',"$1;",$string);

Furthermore numeric entities don't need a trailing semicolon (very stupid, IMHO) to be recognized by browsers. The following line takes care of that:


$string = preg_replace('#(&\#x*)([0–9A-F]+);*#iu',"$1$2;",$string);

on* Attributes


One of the easiest way to do XSS is to use one of the on* attributes, like onclick or onload. With this you can easily execute a script, without the user even having to do something (with onload, etc) or just having to click or hover over something.


We just remove them all with


$string = preg_replace('#(<[^>]+[\s\r\n\"\'])(on|xmlns)[^>]*>#iU',"$1>",$string);


the second kind of attributes we remove here are namespace attributes. If we only want HTML as input, you don't need them. There are some funny exploitable things with XBL or just namespacing XHTML nodes in Mozilla (but it doesn't work, if the site is delivered as text/html).


If you write your own filter, be aware, that browser also parse something like that


<a href="foo"onclick="alert()">bar</a>

*script protocols


As you certainly know, can you use javascript: and vbscript: as protocol handlers instead of http:// and others. Something like <a href="javascript:alert('foobar')">lll</a> executes just nicely if a user clicks on it. We of course remove that as well. IE as also the strange behaviour that something like "<tt>java script :</tt>" is also valid, so we have to check for a whitespace between every character.


$string = preg_replace('#([a-z]*)[\x00-\x20]*=[\x00-\x20]*([\`\'\"]*)[\\x00-\x20]*j[\x00-\x20]*a[\x00-\x20]*v[\x00-\x20]*a[\x00-\x20]*s[\x00-\x20]*c[\x00-\x20]*r[\x00-\x20]*i[\x00-\x20]*p[\x00-\x20]*t[\x00-\x20]*:#iU','$1=$2nojavascript...',$string);
$string = preg_replace('#([a-z]*)[\x00-\x20]*=([\'\"]*)[\x00-\x20]*v[\x00-\x20]*b[\x00-\x20]*s[\x00-\x20]*c[\x00-\x20]*r[\x00-\x20]*i[\x00-\x20]*p[\x00-\x20]*t[\x00-\x20]*:#iU','$1=$2novbscript...',$string);


There are more “dangerous” protocol, which you should get rid of, like:


about, wysiwyg, data, view-source, ms-its, mhtml, shell, lynxexec, lynxcgi, hcp, ms-help, help, disk, vnd.ms.radio, opera, res, resource, chrome, mocha, livescript

javascript in CSS


I didn't know, that this was possible, but IE has this “feature” of allowing javascript with CSS. Is certainly useful in some scenarios, but also opens new exploit possibilities.
Something like


<span style="width: expression(alert('Ping!'));"></span>


leads to an endless loop of alerts... url() expression for loading background images can also have *script: protocol handlers. The following removes them:


$string = preg_replace('#([a-z]*)[\x00-\x20]*=[\x00-\x20]*([\`\'\"]*)[\\x00-\x20]*j[\x00-\x20]*a[\x00-\x20]*v[\x00-\x20]*a[\x00-\x20]*s[\x00-\x20]*c[\x00-\x20]*r[\x00-\x20]*i[\x00-\x20]*p[\x00-\x20]*t[\x00-\x20]*:#iU','$1=$2nojavascript...',$string);
$string = preg_replace('#([a-z]*)[\x00-\x20]*=([\'\"]*)[\x00-\x20]*v[\x00-\x20]*b[\x00-\x20]*s[\x00-\x20]*c[\x00-\x20]*r[\x00-\x20]*i[\x00-\x20]*p[\x00-\x20]*t[\x00-\x20]*:#iU','$1=$2novbscript...',$string);

As mentioned above, the script sometimes removes too much. This regex is an example, it just clears all attributes after the style attribute. But so what, bad input is bad input and I don't care if it removes too much in such a situation (safehtml mentioned above does handle such situations better, btw)


There are more css-tricks possible with instructions like: behavior, include-sorce (NN4 only), moz-binding, content, absolute/fixed (only bad for re-positioning, not executing JS)

prefixed elements


We removed all namespace declarations above, here we remove all elements, which have a prefix, they are not needed in HTML..


$string = preg_replace('#</*\w+:\w[^>]*>#i',,$string);

== unwanted elements ==

There are quite some elements in HTML, which you definitively don't want in something like user comments. We remove them with:

do {
$oldstring = $string;
$string = preg_replace('#</*(applet|meta|xml|blink|link|style|script|embed|object|iframe|frame|frameset|ilayer|layer|bgsound|title|base)[^>]*>#i',,$string);
} while ($oldstring != $string);


The reason for the while loop is, that stuff like


<sc<script>ript>alert('hello')</sc</script>ript>


is completely removed. Again, applying tidy before passing the string to this script would have prevented such comments in the first place.

Conclusion


The script seems to do its job, but I don't claim, it's perfect. Use it at your own risk and combine it with other methods like tidy and striptags.


If you find further holes, please report them to me, so we can improve the script.

Acknowledgements


The following people sent me their input for further improving the cleaning. I like to thank them a lot


* Chris Padfield
* Kevin Melchert
* Roman Ivanov (author of the above mentioned safehtml parser)
* Jared Williams


Links


* http://www.shocking.com/~rsnake/xss.html – XSS Cheatsheet



 
Комментариев нет. [Показать комментарии/форму]