2012-04-25 3 views
1

Я отправил этот вопрос некоторое время назад, и он отлично работает для поиска и «связывания» ссылок с созданных пользователем сообщений. Linkify Regex Function PHP Daring Fireball MethodСмягчение атак xss при построении ссылок

<?php 
if (!function_exists("html")) { 
function html($string){ 
    return htmlspecialchars($string, ENT_QUOTES, 'UTF-8'); 
} 
} 

if (false === function_exists('linkify')): 
    function linkify($str) { 
$pattern = '(?xi)\b((?:(http)s?://|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}/)(?:[^\s()<>]+|\(([^\s()<>]+|(\([^\s()<>]+\)))*\))+(?:\(([^\s()<>]+|(\([^\s()<>]+\)))*\)|[^\s`!()\[\]{};:\'".,<>?«»“”‘’]))'; 
return preg_replace_callback("#$pattern#i", function($matches) { 
    $input = $matches[0]; 
    $url = $matches[2] == 'http' ? $input : "http://$input"; 
    return '<a href="' . $url . '" rel="nofollow" target="_blank">' . "$input</a>"; 
}, $str); 
} 
endif; 

echo "<div>" . linkify(html($row_rsgetpost['userinput'])) . "</div>"; 

?> 

Я обеспокоен тем, что я, возможно, представит угрозу безопасности, вставив пользовательский контент в виде ссылки. Я уже избегаю пользовательского контента, исходящего из моей базы данных, с htmlspecialchars($string, ENT_QUOTES, 'UTF-8'), прежде чем запускать его через функцию привязки и повторять на странице, но я прочитал о OWASP, что ссылки на атрибуты необходимо обрабатывать специально для уменьшения XSS. Я думаю, что эта функция в порядке, поскольку она помещает созданный пользователем контент в двойные кавычки и уже сбежала с htmlspecialchars($string, ENT_QUOTES, 'UTF-8'), но по-настоящему оценила бы кого-то с опытом xss, чтобы подтвердить это. Благодаря!

+1

Если недопустимый ввод предназначен для размещения в href, src или других атрибутах на основе URL-адресов, он должен быть проверен, чтобы убедиться, что он не указывает на неожиданный протокол, особенно ссылки на Javascript. Затем URL-адрес должен быть закодирован на основе контекста отображения, как и любой другой фрагмент данных. Например, URL-адреса, управляемые пользователем, в HREF-ссылках должны быть закодированы атрибутом. Пример приведен в Java. Не знаете, как реализовать в PHP ... http://code.google.com/p/owasp-esapi-java/source/browse/trunk/src/main/java/org/owasp/esapi/codecs/PercentCodec.java – Jeff

+0

-1 Это смущение, вам нужно проверить свой код. – rook

+0

См. Отредактированный вопрос с полным кодом. – Jeff

ответ

0

Ваше регулярное выражение ищет URL-адреса http или https. Это выражение кажется относительно безопасным, поскольку в нем не обнаружено ничего, что не является URL-адресом.

Уязвимость XSS исходит из экранирования url как аргумента html. Это означает, что URL-адрес не может преждевременно покинуть строку url, а затем добавить дополнительные атрибуты в тег html, который упоминал @Rook.

Так что я не могу придумать способ, как атака XSS может быть выполнен следующий код, предложенный @tobyodavies, но без UrlEncode, что делает что-то другое:

$pattern = '(?xi)\b((?:(http)s?://|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}/)(?:[^\s()<>]+|\(([^\s()<>]+|(\([^\s()<>]+\)))*\))+(?:\(([^\s()<>]+|(\([^\s()<>]+\)))*\)|[^\s`!()\[\]{};:\'".,<>?«»“”‘’]))'; 
return preg_replace_callback("#$pattern#i", function($matches) { 
    $input = $matches[0]; 
    $url = $matches[2] == 'http' ? $input : "http://$input"; 
    return '<a href="' . htmlspecialchars($url) . '" rel="nofollow" target="_blank">' . "$input</a>"; 
}, $str); 

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

Теперь создаваемые вами якорные соединения безопасны.

Однако вы также должны дезинфицировать остальную часть текста. Я полагаю, что вы не хотите разрешать какой-либо html вообще и отображать весь html как чистый текст.

+0

Спасибо @d_inevitable. Я надеялся, что вы взглянете на это, потому что исходная функция ссылок - ваша. К сожалению, когда я пытаюсь сделать это (после того, как вы установили опечатку на $ mathes -> $ matches), функция linkify больше не работает. Когда я нажимаю на введенный текст «www.google.com», например, ссылка идет на https://www.mysite.com/directory/http%3A%2F%2Fwww.google.com. Это потому, что исходное регулярное выражение $ pattern больше не может сравниваться с символами urlencoded? Считаете ли вы, что исходная функция «linkify» достаточна, поскольку контент, созданный пользователем, находится внутри двойных кавычек? – Jeff

+0

Да, оригинал достаточно, но менее эффективен. Вы также изменили шаблон, как я? Скобки вокруг http: '(http)'. –

+0

На самом деле я нашел проблему. Это с кодировкой url, которая не должна принимать протокол. Будет внесено редактирование, чтобы заставить его работать. –

1

Перед отправкой в ​​базу данных должно быть NEVER. Это очень серьезная ошибка. Это не только небезопасно, но и нарушает функциональность. Связывание значений строк, является повреждением данных и влияет на сравнение строк. Этот подход небезопасен, поскольку XSS is an output problem. Когда вы вставляете данные в базу данных, вы не знаете, где она появляется на странице. Например, даже если вы, где эта функция следующий код по-прежнему уязвимы для XSS:

Например:

<a href="javascript:alert(1)" \> 

С точки зрения регулярного выражения. Моя первоначальная реакция была, ну это ужасная идея. Нет комментариев о том, как его предположил для работы и интенсивного использования операторов NOT, черный список всегда хуже, чем белый листинг.

Так что я загрузил Regex Buddy и в около 3 минут я обошел ваше регулярное выражение с этим входом:

https://test.com/test'onclick='alert(1);// 

Нет разработчик хочет написать уязвимо, так что они вызваны с расшифровкой в ​​том, как программист думает его приложение работает и как оно работает. В этом случае я бы предположил, что вы никогда не тестировали это регулярное выражение и его грубое упрощение проблемы.

HTMLPurifer - это php-библиотека, предназначенная для очистки HTML, состоит из ТЫСЯЧ регулярных выражений. Он очень медленный, и его обходят довольно регулярно. Поэтому, если вы идете по этому маршруту, обязательно обновляйте его регулярно.

С точки зрения исправления этого недостатка, я думаю, что вам лучше всего использовать htmlspecialchars($string, ENT_QUOTES, 'UTF-8'), а затем принудительно установить, что строка начинается с «http». HTML-кодирование представляет собой форму экранирования, и значение будет автоматически декодироваться таким образом, чтобы URL-адрес был невозможен.

1

Поскольку данные собираются в атрибут, он должен быть URL (или процент) кодируются:

return '<a href="' . urlencode($url) . '" rel="nofollow" target="_blank">' . "$input</a>"; 

Технически он также должен быть затем HTML закодирован

return '<a href="' . htmlspecialchars(urlencode($url)) . '" rel="nofollow" target="_blank">' . "$input</a>"; 

но никакие браузеры Я знаю о заботе, и, следовательно, никто не делает этого, и похоже, что вы уже делаете этот шаг уже, и вы не не делаете этого дважды

+0

Ни один из этих подходов не создает достоверных ссылок HTTP. Этот подход является самопровозглашением. – rook

+0

Спасибо @tobyodavies. Я думаю, что ты на правильном пути, и я попробовал это раньше. К сожалению, это нарушает функцию 'linkify', потому что urlencoded url больше не совпадает с Regex, который определяет ссылку в функции preg_replace_callback. К сожалению, это немного над моей головой ... не уверен, что это возможно. – Jeff

+0

@ Просмотрите, какой возможный недопустимый URL-адрес может избежать кодировки URL? это может оказаться бессмысленным, но оно всегда будет законным и никогда не может быть JS-ссылкой или иметь какие-либо побочные эффекты для DOM). – tobyodavies

0

Во-первых, в документации PHP states htmlspecialchars только ускользает " '&' (амперсанд) становится '&' «"(двойные кавычки) становится '"', когда ENT_NOQUOTES не установлен. «'(одинарная кавычка) становится« ' »(или ') только при установке ENT_QUOTES. «<» (меньше) становится «<» «>» (больше) становится «» > »JavaScript:. До сих пор используется в обычном программировании, так почему: не убежали за меня

.

Во-вторых, if! Html ожидает только тех символов, которые, по вашему мнению, будут введены, а не представления тех символов, которые могут быть введены и считаются действительными. U tf-8 character set, и каждый другой набор символов поддерживает несколько представлений для одного и того же символа. , ваш ложный оператор позволяет делать 0-9 и az, поэтому вам все равно придется беспокоиться о base64 characters.Я бы назвал ваш код хорошей попыткой, но ему нужна тонна очистки. Это или вы могли бы просто использовать htmlpurifier, bypas s. Я думаю, что это удивительно, что вы устанавливаете набор символов в htmlspecialchars, так как большинство программистов не понимают, почему они должны это делать.

Смежные вопросы