Skip to content

Instantly share code, notes, and snippets.

Created September 3, 2013 06:10
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save anonymous/52adda0113428b274c64 to your computer and use it in GitHub Desktop.
Save anonymous/52adda0113428b274c64 to your computer and use it in GitHub Desktop.

Уязвимость XSS в PHP-скриптах и как ее избежать

Все очень просто. XSS — это тип уязвимости, когда злоумышленник умудряется пропихнуть HTML- или JS- код в страницу на твоем сайте. Если ему это удается сделать, то при открытии такой страницы в браузере код скрипта исполняется и может делать любые вещи от имени пользователя, например, воровать его куки (чтобы злоумышенник потом с их помощью зашел на сайт), рассылать спам, перенаправлять пользователей на другой сайт, в общем код может сделать много нехороших вещей.

Самый простой пример, когда можно передать вредные данные через GET-параметр, например, http://example.com?q=[... html и js код ...]. Но вообще, XSS атаку можно провести и через любые другие данные, например, POST-, куки, HTTP-заголовки, данные из базы (которые хакер записал туда раньше). То есть на более-менее сложном сайте невозможно отфильтровать все входные данные, это бесперспективный путь.

Также, пытаться фильтровать GET/POST не очень перспективно, так как есть очень много способов подснуть злой код (примеры: https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet ). Трудно написать фильтр, который сможет ловить все эти коды.

Пример XSS

Прежде чем говорить о методах борьбы, рассмотрим 2 простых примера. Допустим, школьник Вася сделал на своем сайте скрипт search.php для поиска информации на сайте. Данные для поиска передаются через GET-параметр и не фильтруются. Вот, как выглядит код:

....
$query = $_GET['q'];
echo "<p>Вы искали: $query</p>";
.... дальше идет код вывода результатов поиска ...

Злоумышленник может сделать ссылку: /search.php?q=<script>украсть все куки пользователя</скрипт>

Содержимое параметра q без изменений вставится в страницу и получится код:

<p>Вы искали: <script>украсть все куки пользователя</script>

Злоумышленник посылает сссылку Васе (автору сайта), тот ее открывает в браузере, запускается скрипт и ворует куки Васи. Злоумышленник выкладывает куки на анонимном форуме и все его посетители дружно издеваются над сайтом Васи.

Пример 2

Наученный горьким опытом, Вася почитал устаревшие учебники по PHP4 и, как там советовалось, поставил фильтр, не пропускающий угловые скобки и слово «script». И переделал свой код:

....
$query = $_GET['q'];
... проверка на наличие угловых скобок или слова скрипт ....

echo "<p>Вы искали: $query</p>";
.... дальше идет код вывода результатов поиска ...
echo "Искать еще: <input type=text value='$query'><button type=button>Искать</button>";
.....

Хакер так просто не сдается. Он делает ссылку вида

/search.php?q=' autofocus onfocus='злой код'

и снова отправляет ее админу Васе. Админ открывает страницу, и запускается злой скрипт. Почему? Посмотрим, что получилось при подстановке параметра q в input type=text:

Искать еще: <input type=text value='' autofocus onfocus='злой код'
'><button type=button>Искать</button>

Как видим, за счет кавычки злоумышленник смог вставить свой текст как оттрибуты тега input. Аттрибут autofocus вызывает автоматическую установку курсора в поле при загрузке страницы, а аттрибут onfocus содержит скрипт, который срабатывает при установке курсора в поле. Вася опять попался (и в этот раз хакер отыгрался на его сайте по полной программе).

Не хочешь быть как Вася? Читай дальше.

Средства борьбы

Средство борьбы одно и простое: все данные, выводимые из переменных (неважно, откуда они пришли), в HTML код, надо пропускать через функцию htmlspecialchars (читай мануал по ней http://php.net/manual/ru/function.htmlspecialchars.php ):

echo "<p>Вы искали: ".htmlspecialchars($query, ENT_QUOTES)."</p>";
echo "Искать еще: <input type=text value='".htmlspecialchars($query)."'><button type=button>Искать</button>";

Так надо делать со всеми переменными без исключения, значения которых выводятся на странице. Эта функция, htmlspecialchars, заменяет символы <, >, ", ', & на HTML-сущности так, что любые теги и кавычки не ломают твой HTML, а просто выводятся как текст.

Теперь хакер может передавать любые спецсимволы в параметре q и уязвимости не будет, так как например тег <div> заменится на текст &lt; div &gt; который отобразится браузером как <div> (не как тег, а как текст).

Можешь сделать этот скрипт, и проверить сам.

Если лень писать каждый раз htmlspecialchars($query, ENT_QUOTES), можно сделать функцию с коротким именем:

function h($text) {
    return htmlspecialchars($text, ENT_QUOTES);
}

От чего не поможет htmlspecialchars

Если ты на сайте разрешаешь пользователям вводить ссылки (например, в разделе «О себе»), то надо проверять, что они начинаются с http:// или https:// . Иначе пользователь подсунет ссылку вида data://... или javascript:// .... при клике по которой выполнится код. Конечно, ему надо еще заманить других пользователей кликнуть по ней, но наверняка есть способы для этого. htmlspecialchars тут не спасет, но поможет проверка ссылки регулярным выражением на правильность.

Дополнительно защищаем куки

Дополнительная защита никогда не помешает, верно? У кук уже несколько лет есть специальный дополнительный параметр: httpOnly. Если ты укажешь его при создании куки, то такая кука будет недоступна яваскрипту на странице и злоумышленник даже найдя XSS не сможет украсть куки (но другие нехорошие вещи он сможет сделать, так что защищаться все равно надо).

Вот, как создать http-only куку в PHP:

setcookie ('auth', '12344567890', 0, null, null, false, true)

последний параметр, true, включает опцию http-only. Думаю, стоит включать эту полезную опцию для всех кук, которые как-то авторизуют пользователя. Мануал: http://php.net/manual/en/function.setcookie.php

Повторим еще раз

  • Выводим данные только через htmlspecialchars
  • Проверяем ссылки, пришедшие от пользователей, регуляркой
  • Используем httpOnly куки

Дополнительное чтение (на русском)

http://archive-ipq-co.narod.ru

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment