Как предотвратить XSS (межсайтовый скриптинг), используя только HTML и PHP?
Я видел множество других сообщений по этой теме, но я не нашел статью, в которой ясно и кратко сказано, как фактически предотвратить XSS.
Как предотвратить XSS (межсайтовый скриптинг), используя только HTML и PHP?
Я видел множество других сообщений по этой теме, но я не нашел статью, в которой ясно и кратко сказано, как фактически предотвратить XSS.
В основном вам нужно использовать функцию htmlspecialchars()
когда вы хотите вывести что-то в браузер, который поступает с пользовательского ввода.
Правильный способ использования этой функции:
echo htmlspecialchars($string, ENT_QUOTES, 'UTF-8');
В Google Code University также есть эти образовательные видеоролики в Web Security:
Одной из моих любимых ссылок на OWASP является объяснение межсайтовых сценариев, поскольку, хотя существует большое количество векторов атак XSS, соблюдение следующих нескольких правил может в значительной степени защитить от большинства из них!
Одним из наиболее важных шагов является дезинфекция любого пользовательского ввода до его обработки и/или возврата в браузер. PHP имеет некоторые функции filter, которые можно использовать.
Форма, которую обычно имеют XSS-атаки, заключается в том, чтобы вставить ссылку на какой-то javascript за пределами площадки, который содержит вредоносные намерения для пользователя. Подробнее об этом здесь.
Вы также захотите проверить свой сайт - я могу рекомендовать дополнение Firefox XSS Me.
В порядке предпочтения:
{{ var|e('html_attr') }}
htmlentities($var, ENT_QUOTES | ENT_HTML5, $charset)
и убедитесь, что в остальном документе используется тот же набор символов, что и $charset
. В большинстве случаев 'UTF-8'
- желаемый набор символов.Кроме того, убедитесь, что escape на выходе, а не на входе.
Перекрестная публикация этого в виде сводной ссылки из бета-версии документации SO, которая выходит в автономном режиме.
Межсайтовый скриптинг - это непреднамеренное выполнение удаленного кода веб-клиентом. Любое веб-приложение может представлять себя для XSS, если оно принимает данные от пользователя и выводит их непосредственно на веб-странице. Если ввод включает HTML или JavaScript, удаленный код может быть выполнен, когда этот контент отображается веб-клиентом.
Например, если сторонняя сторона содержит файл JavaScript:
// http://example.com/runme.js
document.write("I'm running");
И приложение PHP напрямую выводит строку, переданную в него:
<?php
echo '<div>' . $_GET['input'] . '</div>';
Если непроверенный параметр GET содержит <script src="http://example.com/runme.js"></script>
то вывод сценария PHP будет выглядеть так:
<div><script src="http://example.com/runme.js"></script></div>
Будет запущен сторонний JavaScript, и пользователь увидит "Я бегу" на веб-странице.
Как правило, никогда не доверяйте данным, поступающим от клиента. Каждое значение GET, POST и cookie может быть чем угодно, и поэтому должно быть проверено. При выводе любого из этих значений избегайте их, чтобы они не оценивались неожиданным образом.
Имейте в виду, что даже в самых простых приложениях данные могут перемещаться, и будет трудно отслеживать все источники. Поэтому лучше всегда избегать вывода.
PHP предоставляет несколько способов избежать вывода в зависимости от контекста.
Функции фильтра PHPs позволяют вводить данные в сценарий php для дезинфекции или проверки различными способами. Они полезны при сохранении или выводе клиентского ввода.
htmlspecialchars
преобразует любые "специальные символы HTML" в свои HTML-кодировки, что означает, что они не будут обрабатываться как стандартный HTML. Чтобы исправить наш предыдущий пример, используя этот метод:
<?php
echo '<div>' . htmlspecialchars($_GET['input']) . '</div>';
// or
echo '<div>' . filter_input(INPUT_GET, 'input', FILTER_SANITIZE_SPECIAL_CHARS) . '</div>';
Будет вывод:
<div><script src="http://example.com/runme.js"></script></div>
Все внутри <div>
не будет интерпретироваться браузером как тег JavaScript, а как простой текстовый узел. Пользователь безопасно увидит:
<script src="http://example.com/runme.js"></script>
При выводе динамически сгенерированного URL-адреса PHP предоставляет функцию urlencode
для безопасного вывода действительных URL-адресов. Так, например, если пользователь может вводить данные, которые становятся частью другого параметра GET:
<?php
$input = urlencode($_GET['input']);
// or
$input = filter_input(INPUT_GET, 'input', FILTER_SANITIZE_URL);
echo '<a href="http://example.com/page?input="' . $input . '">Link</a>';
Любой вредоносный ввод будет преобразован в закодированный параметр URL.
Иногда вам захочется отправить HTML или другой вид ввода кода. Вам нужно будет вести список разрешенных слов (белый список) и неавторизованных (черный список).
Вы можете скачать стандартные списки, доступные на веб-сайте OWASP AntiSamy. Каждый список подходит для определенного вида взаимодействия (ebay api, tinyMCE и т.д.). И это с открытым исходным кодом.
Существуют библиотеки для фильтрации HTML и предотвращения XSS-атак для общего случая и выполнения по крайней мере так же, как списки AntiSamy с очень простым использованием. Например, у вас есть очиститель HTML
Многие структуры помогают обрабатывать XSS по-разному. Когда вы катаетесь самостоятельно или если есть какая-то проблема XSS, мы можем использовать filter_input_array (доступно в PHP 5> = 5.2.0, PHP 7.) Обычно я добавляю этот фрагмент к моему SessionController, потому что все вызовы проходят там до того, как любой другой контроллер взаимодействует с данными. Таким образом, все входные данные пользователя дезинфицируются в одном центральном месте. Если это делается в начале проекта или до того, как ваша база данных отравлена, у вас не должно быть никаких проблем в момент выхода... останавливает мусор, мусор.
/* Prevent XSS input */
$_GET = filter_input_array(INPUT_GET, FILTER_SANITIZE_STRING);
$_POST = filter_input_array(INPUT_POST, FILTER_SANITIZE_STRING);
/* I prefer not to use $_REQUEST...but for those who do: */
$_REQUEST = (array)$_POST + (array)$_GET + (array)$_REQUEST;
Вышеупомянутое удалит ВСЕ теги HTML и скриптов. Если вам нужно решение, которое позволяет безопасные теги, основанные на белом списке, ознакомьтесь с HTML-очистителем.
Если ваша база данных уже отравлена или вы хотите иметь дело с XSS во время вывода, OWASP рекомендует создавать пользовательскую функцию-обертку для echo
и использовать ее в любом случае вы выставляете значения, заданные пользователем:
//xss mitigation functions
function xssafe($data,$encoding='UTF-8')
{
return htmlspecialchars($data,ENT_QUOTES | ENT_HTML401,$encoding);
}
function xecho($data)
{
echo xssafe($data);
}
<?php
function xss_clean($data)
{
// Fix &entity\n;
$data = str_replace(array('&','<','>'), array('&amp;','&lt;','&gt;'), $data);
$data = preg_replace('/(&#*\w+)[\x00-\x20]+;/u', '$1;', $data);
$data = preg_replace('/(&#x*[0-9A-F]+);*/iu', '$1;', $data);
$data = html_entity_decode($data, ENT_COMPAT, 'UTF-8');
// Remove any attribute starting with "on" or xmlns
$data = preg_replace('#(<[^>]+?[\x00-\x20"\'])(?:on|xmlns)[^>]*+>#iu', '$1>', $data);
// Remove javascript: and vbscript: protocols
$data = 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...', $data);
$data = 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...', $data);
$data = preg_replace('#([a-z]*)[\x00-\x20]*=([\'"]*)[\x00-\x20]*-moz-binding[\x00-\x20]*:#u', '$1=$2nomozbinding...', $data);
// Only works in IE: <span style="width: expression(alert('Ping!'));"></span>
$data = preg_replace('#(<[^>]+?)style[\x00-\x20]*=[\x00-\x20]*[`\'"]*.*?expression[\x00-\x20]*\([^>]*+>#i', '$1>', $data);
$data = preg_replace('#(<[^>]+?)style[\x00-\x20]*=[\x00-\x20]*[`\'"]*.*?behaviour[\x00-\x20]*\([^>]*+>#i', '$1>', $data);
$data = preg_replace('#(<[^>]+?)style[\x00-\x20]*=[\x00-\x20]*[`\'"]*.*?s[\x00-\x20]*c[\x00-\x20]*r[\x00-\x20]*i[\x00-\x20]*p[\x00-\x20]*t[\x00-\x20]*:*[^>]*+>#iu', '$1>', $data);
// Remove namespaced elements (we do not need them)
$data = preg_replace('#</*\w+:\w[^>]*+>#i', '', $data);
do
{
// Remove really unwanted tags
$old_data = $data;
$data = preg_replace('#</*(?:applet|b(?:ase|gsound|link)|embed|frame(?:set)?|i(?:frame|layer)|l(?:ayer|ink)|meta|object|s(?:cript|tyle)|title|xml)[^>]*+>#i', '', $data);
}
while ($old_data !== $data);
// we are done...
return $data;
}
Вы также можете установить некоторые заголовки ответов HTTP, связанные с XSS, с помощью header(...)
X-XSS-Protection "1; mode = block"
убедитесь, что включен режим защиты браузера XSS.
Content-Security-Policy "default-src 'self';..."
чтобы включить защиту содержимого на стороне браузера. См. Этот раздел для сведений о политике безопасности контента (CSP): http://content-security-policy.com/ Особенно рекомендуется настроить CSP для блокировки встроенных скриптов и внешних источников script для XSS.
для общей группы полезных заголовков HTTP-ответа, касающихся безопасности вашего webapp, посмотрите на OWASP: https://www.owasp.org/index.php/List_of_useful_HTTP_headers
Используйте htmlspecialchars
на PHP
. На HTML старайтесь избегать использования:
element.innerHTML = "…";
element.outerHTML = "…";
document.write(…);
document.writeln(…);
где var
контролируется пользователем.
Также, очевидно, избегайте eval(var)
,
если вам нужно использовать какой-либо из них, попробуйте JS выйти из них, HTML сбежать от них, и вам, возможно, придется сделать еще кое-что, но для основ этого должно быть достаточно.