Я настроил PHP так, что магические кавычки включены, а глобальные регистры отключены.
Я изо всех сил стараюсь всегда вызывать htmlentities () для всех выводимых мной данных, полученных на основе пользовательского ввода.
Я также иногда ищу в своей базе данных общие вещи, используемые в прикрепленном xss, такие как ...
<script
Что еще мне следует делать и как я могу убедиться, что то, что я пытаюсь сделать, выполнено всегда.






Для большинства сайтов достаточно экранирования всего пользовательского ввода. Также убедитесь, что идентификаторы сеанса не попадают в URL-адрес, чтобы их нельзя было украсть из ссылки Referer на другой сайт. Кроме того, если вы разрешаете пользователям отправлять ссылки, убедитесь, что ссылки протокола javascript: не разрешены; они будут выполнять сценарий, как только пользователь щелкает ссылку.
Есть много способов сделать XSS (см. http://ha.ckers.org/xss.html), и их очень сложно уловить.
Я лично делегирую это текущему фреймворку, который я использую (например, Code Igniter). Хотя он и не идеален, он может уловить больше, чем мои ручные рутины.
Если вас беспокоят XSS-атаки, решением будет кодирование ваших выходных строк в HTML. Если вы не забываете кодировать каждый выходной символ в формате HTML, нет никакого способа выполнить успешную атаку XSS.
Прочитайте больше: Очистка пользовательских данных: как и где это делать
Экранирование ввода - не лучшее, что вы можете сделать для успешного предотвращения XSS. Также вывод должен быть экранирован. Если вы используете механизм шаблонов Smarty, вы можете использовать модификатор |escape:'htmlall' для преобразования всех конфиденциальных символов в объекты HTML (я использую собственный модификатор |e, который является псевдонимом для вышеупомянутого).
Мой подход к безопасности ввода / вывода:
htmlspecialchars может не быть вашим другом: stackoverflow.com/questions/110575/…
@Cheekysoft: просто установите соответствующие флаги
Как я думаю, было бы лучше сначала сбежать, а затем сохранить его в базе данных, потому что таким образом вам придется сбежать только один раз, но если вы просто сохраните его в БД и избегаете каждый раз, когда пользователь посещает сайт, это может заставить работать немного загруженный сервер. И большая часть экранирования одинакова для PHP и Node.js. Так что лучше сначала сбежать, а потом сохранить.
@AbdulJabbarWebBestow абсолютно нет. База данных - это место, где вы храните данные в формате, не зависящем от вывода. Для различных устройств вывода требуются разные правила экранирования, таким образом, экранируя вывод HTML перед обращением к базе данных, вы блокируете себя от написания API, экспорта PDF и т. д. Не беспокойтесь о загрузке сервера. Их работа - загружаться.
@ MichałRudnicki На самом деле я не занимаюсь глажкой, но не могли бы вы привести несколько разных примеров, когда нам нужно другое экранирование, потому что, насколько я знаю, экранирование одинаково для всех. Что касается нагрузки на базу данных, то, вероятно, наша обязанность - максимально снизить нагрузку, иначе это выйдет из строя ваш сервер. И в большинстве случаев около 75% это html, который требует такого же экранирования, и когда приходит время для PDF, или вы можете использовать функции декодирования для обратного.
@AbdulJabbarWebBestow Quotes " необходимо экранировать как " для использования в HTML, но \" для использования в большинстве других языков.
«Волшебные цитаты» - это паллиативное средство от некоторых из наихудших недостатков XSS, которое работает, избегая всего при вводе, что является неправильным по замыслу. Единственный случай, когда его можно было бы использовать, - это когда вам абсолютно необходимо использовать существующее приложение PHP, которое, как известно, написано небрежно в отношении XSS. (В этом случае у вас серьезные проблемы даже с «волшебными кавычками».) При разработке собственного приложения вы должны отключить «волшебные кавычки» и вместо этого следовать XSS-безопасным методам.
XSS, уязвимость межсайтового сценария, возникает, когда приложение включает строки из внешних источников (вводимые пользователем, полученные с других веб-сайтов и т. д.) В свой [X] HTML, CSS, ECMAscript или другой анализируемый браузером вывод без надлежащего экранирования, надеясь что специальные символы, такие как «меньше» (в [X] HTML), одинарные или двойные кавычки (ECMAscript), никогда не появятся. Правильным решением этой проблемы является экранирование строк в соответствии с правилами языка вывода: использование сущностей в [X] HTML, обратная косая черта в ECMAscript и т. д.
Поскольку сложно отследить, что является ненадежным и что должно быть исключено, рекомендуется всегда избегать всего, что является «текстовой строкой», а не «текстом с разметкой» в таком языке, как HTML. Некоторые среды программирования упрощают эту задачу, вводя несколько несовместимых типов строк: «строка» (обычный текст), «строка HTML» (разметка HTML) и так далее. Таким образом, прямое неявное преобразование из «строки» в «строку HTML» будет невозможно, и единственный способ, которым строка может стать разметкой HTML, - это передать ее через функцию экранирования.
«Зарегистрируйте глобальные объекты», хотя его отключение, безусловно, хорошая идея, решает проблему, совершенно отличную от XSS.
Не используйте глобальные регистры. Они упрощают написание небезопасного кода и были обесценены с момента публикации.
Я имел в виду, конечно, отключение глобальных регистров, а не включение. Опечатка.
Используйте существующую библиотеку очистки пользовательского ввода для очистки пользовательского ввода все. Если вы не приложите к этому много усилий, реализация этого сама никогда не сработает.
Это большой вопрос.
Во-первых, не экранируйте текст при вводе, кроме как для того, чтобы сделать его безопасным для хранения (например, для помещения в базу данных). Причина этого в том, что вы хотите сохранить то, что было введено, чтобы вы могли контекстно представить это в разных местах и способами. Внесение здесь изменений может поставить под угрозу вашу более позднюю презентацию.
Когда вы идете на презентацию, отфильтруйте данные, которых там быть не должно. Например, если нет причин для появления javascript, найдите его и удалите. Легкий способ сделать это - использовать функцию strip_tags и представить только разрешенные вами HTML-теги.
Затем возьмите то, что у вас есть, и передайте ему htmlentities или htmlspecialchars, чтобы изменить то, что есть, на символы ascii. Делайте это в зависимости от контекста и того, что вы хотите получить.
Я бы также предложил отключить Magic Quotes. Он был удален из PHP 6 и считается плохой практикой его использования. Подробности на http://us3.php.net/magic_quotes
Подробнее см. http://ha.ckers.org/xss.html
Это не полный ответ, но, надеюсь, достаточно, чтобы помочь вам начать работу.
Создавать любые сеансовые файлы cookie (или все файлы cookie), которые вы используете HttpOnly. В этом случае большинство браузеров скрывают значение cookie от JavaScript. Пользователь по-прежнему может вручную копировать файлы cookie, но это помогает предотвратить прямой доступ к сценарию. У StackOverflow была эта проблема во время бета-тестирования.
Это не решение, просто еще один кирпич в стене
Лично я бы отключил magic_quotes. В PHP5 + он отключен по умолчанию, и лучше кодировать так, как будто его вообще нет, поскольку он не ускользает от всего и будет удален из PHP6.
Далее, в зависимости от того, какой тип пользовательских данных вы фильтруете, будет зависеть, что делать дальше, например. если это просто текст, например имя, затем strip_tags(trim(stripslashes())); или для проверки диапазонов используйте регулярные выражения.
Если вы ожидаете определенный диапазон значений, создайте массив допустимых значений и разрешите только эти значения через (in_array($userData, array(...))).
Если вы проверяете числа, используйте is_numeric для принудительного применения целых чисел или приведения к определенному типу, это должно предотвратить попытки людей вместо этого отправлять строки.
Если у вас есть PHP5.2 +, подумайте о том, чтобы посмотреть на фильтр() и использовать это расширение, которое может фильтровать различные типы данных, включая адреса электронной почты. Документация не очень хорошая, но улучшается.
Если вам нужно обрабатывать HTML, вам следует подумать о чем-то вроде Входной фильтр PHP или Очиститель HTML. HTML Purifier также проверит HTML на соответствие. Я не уверен, что Input Filter все еще разрабатывается. Оба позволят вам определить набор тегов, которые можно использовать, и какие атрибуты разрешены.
Что бы вы ни выбрали, всегда помните, никогда не доверяйте чему-либо, что приходит в ваш PHP-скрипт от пользователя (включая вас самих!).
rikh Writes:
I do my best to always call htmlentities() for anything I am outputing that is derived from user input.
См. Эссе Джоэла на Код выглядит неправильно для помощи в этом
Все эти ответы хороши, но, по сути, решение XSS будет заключаться в том, чтобы прекратить создание HTML-документов путем манипулирования строками.
Фильтрация ввода - это всегда хорошая идея для любого приложения.
Экранирование вашего вывода с помощью htmlentities () и друзей должно работать, пока оно используется правильно, но это HTML-эквивалент создания SQL-запроса путем объединения строк с mysql_real_escape_string ($ var) - он должен работать, но меньшее количество вещей может проверить вашу работу , так сказать, по сравнению с подходом вроде использования параметризованных запросов.
Долгосрочное решение должно заключаться в том, чтобы приложения создавали страницу внутренне, возможно, с использованием стандартного интерфейса, такого как DOM, а затем использовали библиотеку (например, libxml) для обработки сериализации в XHTML / HTML / и т. д. Конечно, нам еще далеко до того, чтобы это стало достаточно популярным и быстрым, но пока мы должны создавать наши HTML-документы с помощью строковых операций, а это по своей сути более рискованно.
Я считаю, что при вводе ничего не следует избегать, только при выводе. Поскольку (в большинстве случаев) вы не можете предполагать, что знаете, куда идут эти данные. Например, если у вас есть форма, которая принимает данные, которые позже появляются в отправляемом вами электронном письме, вам нужно другое экранирование (в противном случае злонамеренный пользователь может переписать ваши заголовки электронной почты).
Другими словами, вы можете сбежать только в самый последний момент, когда данные «покидают» ваше приложение:
Коротко:
Esp # 3 произойдет, если вы экранируете данные на входном слое (или вам нужно снова отключить экранирование и т. д.).
PS: Я поддержу совет не использовать magic_quotes, это чистое зло!
Бонусный раунд: WordPress перешел во владение XSS через усечение столбцов MySQL в 2015 году благодаря фильтрации на входе, а не на выходе.
Я считаю, что использование этой функции помогает исключить множество возможных атак xss:
<?php
function h($string, $esc_type = 'htmlall')
{
switch ($esc_type) {
case 'css':
$string = str_replace(array('<', '>', '\'), array('<', '>', '/'), $string);
// get rid of various versions of javascript
$string = preg_replace(
'/j\s*[\\]*\s*a\s*[\\]*\s*v\s*[\\]*\s*a\s*[\\]*\s*s\s*[\\]*\s*c\s*[\\]*\s*r\s*[\\]*\s*i\s*[\\]*\s*p\s*[\\]*\s*t\s*[\\]*\s*:/i',
'blocked', $string);
$string = preg_replace(
'/@\s*[\\]*\s*i\s*[\\]*\s*m\s*[\\]*\s*p\s*[\\]*\s*o\s*[\\]*\s*r\s*[\\]*\s*t/i',
'blocked', $string);
$string = preg_replace(
'/e\s*[\\]*\s*x\s*[\\]*\s*p\s*[\\]*\s*r\s*[\\]*\s*e\s*[\\]*\s*s\s*[\\]*\s*s\s*[\\]*\s*i\s*[\\]*\s*o\s*[\\]*\s*n\s*[\\]*\s*/i',
'blocked', $string);
$string = preg_replace('/b\s*[\\]*\s*i\s*[\\]*\s*n\s*[\\]*\s*d\s*[\\]*\s*i\s*[\\]*\s*n\s*[\\]*\s*g:/i', 'blocked', $string);
return $string;
case 'html':
//return htmlspecialchars($string, ENT_NOQUOTES);
return str_replace(array('<', '>'), array('<' , '>'), $string);
case 'htmlall':
return htmlentities($string, ENT_QUOTES);
case 'url':
return rawurlencode($string);
case 'query':
return urlencode($string);
case 'quotes':
// escape unescaped single quotes
return preg_replace("%(?<!\\)'%", "\'", $string);
case 'hex':
// escape every character into hex
$s_return = '';
for ($x=0; $x < strlen($string); $x++) {
$s_return .= '%' . bin2hex($string[$x]);
}
return $s_return;
case 'hexentity':
$s_return = '';
for ($x=0; $x < strlen($string); $x++) {
$s_return .= '&#x' . bin2hex($string[$x]) . ';';
}
return $s_return;
case 'decentity':
$s_return = '';
for ($x=0; $x < strlen($string); $x++) {
$s_return .= '&#' . ord($string[$x]) . ';';
}
return $s_return;
case 'javascript':
// escape quotes and backslashes, newlines, etc.
return strtr($string, array('\'=>'\\',"'"=>"\'",'"'=>'\"',"\r"=>'\r',"\n"=>'\n','</'=>'</'));
case 'mail':
// safe way to display e-mail address on a web page
return str_replace(array('@', '.'),array(' [AT] ', ' [DOT] '), $string);
case 'nonstd':
// escape non-standard chars, such as ms document quotes
$_res = '';
for($_i = 0, $_len = strlen($string); $_i < $_len; $_i++) {
$_ord = ord($string{$_i});
// non-standard char, escape it
if ($_ord >= 126){
$_res .= '&#' . $_ord . ';';
} else {
$_res .= $string{$_i};
}
}
return $_res;
default:
return $string;
}
}
?>
Я считаю, что лучший способ - использовать класс, который позволяет вам привязать ваш код, чтобы вам никогда не приходилось беспокоиться о ручном экранировании ваших данных.
Трудно реализовать тщательное предотвращение внедрения sql / xss-инъекций на сайте, который не вызывает ложных срабатываний. В CMS конечный пользователь может захотеть использовать <script> или <object>, который ссылается на элементы с другого сайта.
Я рекомендую всем пользователям установить FireFox с NoScript ;-)
В этом я полагаюсь на PHPTAL.
В отличие от Smarty и обычного PHP, он по умолчанию экранирует весь вывод. Это большая победа для безопасности, потому что ваш сайт не станет надежным, если вы где-то забудете htmlspecialchars() или |escape.
XSS - это атака, специфичная для HTML, поэтому вывод HTML - правильное место для ее предотвращения. Вы не должны пытаться предварительно фильтровать данные в базе данных, потому что вам может потребоваться вывести данные на другой носитель, который не принимает HTML, но имеет свои собственные риски.
SQL не выполняет JavaScript. Преобразование данных в безопасное подмножество, общее для HTML, SQL, почты и т. д., Слишком ограничивает и не устраняет риск полностью. Правильное экранирование вывода HTML является пуленепробиваемым для HTML. Для правильного экранирования SQL используйте инструменты SQL!
Библиотека шаблонов. Или, по крайней мере, это то, что должны делать библиотеки шаблонов. Для предотвращения XSS выход все должен быть закодирован. Это не задача основной логики приложения / управления, она должна выполняться исключительно методами вывода.
Если вы добавите htmlentities () в свой код, общий дизайн будет неправильным. И, как вы предполагаете, вы можете пропустить одно или два места. Вот почему единственное решение - это строгое кодирование html. Выходные переменные -> когда записываются в поток html / xml.
К сожалению, большинство библиотек шаблонов php добавляют только свой собственный синтаксис шаблонов, но не заботятся о кодировке вывода, локализации, проверке HTML или чем-нибудь важном. Может быть, кто-то еще знает подходящую библиотеку шаблонов для php?
Я полностью согласен и могу сказать, что лучшая библиотека шаблонов - это xsl.
Вы должны, по крайней мере, проверить все данные, поступающие в базу данных. И попробуйте также проверить все данные, покидающие базу данных.
mysql_real_escape_string хорош для предотвращения SQL-инъекций, но XSS сложнее. По возможности вы должны использовать preg_match, stip_tags или htmlentities!
Наилучшим текущим методом предотвращения XSS в приложении PHP является очиститель HTML (http://htmlpurifier.org/). Одним из незначительных недостатков является то, что это довольно большая библиотека, и ее лучше всего использовать с кешем кода операции, таким как APC. Вы можете использовать это в любом месте, где на экран выводится ненадежный контент. Это гораздо более тщательно, чем htmlentities, htmlspecialchars, filter_input, filter_var, strip_tags и т. д.
htmlentities () - это перебор, и он чувствителен к кодировке. htmlspecialchars () также защищает.