Лучший способ обеспечить безопасность и избежать XSS с помощью введенных пользователем URL - PullRequest
50 голосов
/ 15 октября 2008

У нас есть приложение с высоким уровнем безопасности, и мы хотим, чтобы пользователи могли вводить URL-адреса, которые будут видеть другие пользователи.

Это создает высокий риск взлома XSS - пользователь может потенциально ввести javascript, который в итоге выполняет другой пользователь. Поскольку мы храним конфиденциальные данные, важно, чтобы этого никогда не происходило.

Каковы лучшие методы борьбы с этим? Достаточно ли хорош один белый список безопасности или шаблон побега?

Любые рекомендации по работе с перенаправлениями (например, сообщение «эта ссылка выходит за пределы нашего сайта» на странице предупреждения перед переходом по ссылке)

Есть ли аргумент, чтобы вообще не поддерживать введенные пользователем ссылки?


Пояснение:

В основном наши пользователи хотят ввести:

1017 * stackoverflow.com *

И вывести его другому пользователю:

<a href="http://stackoverflow.com">stackoverflow.com</a>

Что меня действительно беспокоит, так это то, что они используют это во взломе XSS. То есть они вводят:

предупреждение ( 'взломан!');

Таким образом, другие пользователи получают эту ссылку:

<a href="alert('hacked!');">stackoverflow.com</a>

Мой пример - просто объяснить риск - я хорошо знаю, что javascript и URL-адреса - это разные вещи, но, позволяя им вводить последние, они могут выполнять первые.

Вы будете удивлены, сколько сайтов вы можете взломать с помощью этого трюка - HTML еще хуже. Если они знают, что делать со ссылками, они также знают, что нужно очистить <iframe>, <img> и умные ссылки CSS?

Я работаю в среде с высоким уровнем безопасности - один взлом XSS может привести к очень большим потерям для нас. Я счастлив, что мог бы создать Regex (или использовать одно из лучших предложений), который мог бы исключить все, что я мог придумать, но будет ли этого достаточно?

Ответы [ 10 ]

54 голосов
/ 15 октября 2008

Если вы считаете, что URL не могут содержать код, подумайте еще раз!

https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet

Прочтите это и плачьте.

Вот как мы это делаем при переполнении стека:

/// <summary>
/// returns "safe" URL, stripping anything outside normal charsets for URL
/// </summary>
public static string SanitizeUrl(string url)
{
    return Regex.Replace(url, @"[^-A-Za-z0-9+&@#/%?=~_|!:,.;\(\)]", "");
}
13 голосов
/ 17 октября 2008

Процесс предоставления ссылки "безопасной" должен проходить через три или четыре шага:

  • Unescape / перекодировать заданную вами строку (RSnake задокументировал ряд трюков на http://ha.ckers.org/xss.html, которые используют экранирование и кодировки UTF).
  • Очистите ссылку: регулярные выражения - хорошее начало - обязательно обрежьте строку или выбросьте ее, если она содержит "(или все, что вы используете для закрытия атрибутов в выходных данных); Если вы делаете ссылки только в качестве ссылки на другую информацию вы также можете принудительно установить протокол в конце этого процесса - если часть перед первым двоеточием не является 'http' или 'https', тогда добавьте 'http://' к началу. Это позволяет вам создавать полезные ссылки из неполного ввода, которые пользователь вводит в браузер, и дает вам последний шанс споткнуться о любое зло, которое кто-то пытался проникнуть.
  • Убедитесь, что результатом является правильно сформированный URL (протокол: //host.domain [: порт] [/ путь] [/ [файл]] [? QueryField = queryValue] [#anchor]).
  • Возможно, проверьте результат по черному списку сайта или попробуйте получить его с помощью какого-либо средства проверки на вредоносное ПО.

Если безопасность является приоритетом, я надеюсь, что пользователи простят немного паранойи в этом процессе, даже если в конечном итоге он выбрасывает некоторые безопасные ссылки.

8 голосов
/ 05 апреля 2013

Использовать библиотеку, такую ​​как OWASP-ESAPI API:

Прочитайте следующее:

Например:

$url = "http://stackoverflow.com"; // e.g., $_GET["user-homepage"];
$esapi = new ESAPI( "/etc/php5/esapi/ESAPI.xml" ); // Modified copy of ESAPI.xml
$sanitizer = ESAPI::getSanitizer();
$sanitized_url = $sanitizer->getSanitizedURL( "user-homepage", $url );

Другим примером является использование встроенной функции. PHP-функция filter_var является примером:

$url = "http://stackoverflow.com"; // e.g., $_GET["user-homepage"];
$sanitized_url = filter_var($url, FILTER_SANITIZE_URL);

Использование filter_var разрешает вызовы JavaScript и отфильтровывает схемы, которые не являются ни http, ни https. Использование OWASP ESAPI Sanitizer , вероятно, лучший вариант.

Еще одним примером является код из WordPress :

Кроме того, поскольку нет способа узнать, где ссылки URL (т. Е. Это может быть действительный URL, но содержание URL может быть вредным), Google имеет безопасный просмотр API, который вы можно позвонить:

Свернуть свое регулярное выражение для санитарии проблематично по нескольким причинам:

  • Если вы не Джон Скит, в коде будут ошибки.
  • Существующие API имеют много часов обзора и тестирования.
  • Существующие API проверки URL учитывают интернационализацию.
  • Существующие API будут обновляться в соответствии с новыми стандартами.

Другие вопросы для рассмотрения:

  • Какие схемы вы разрешаете (допустимы file:/// и telnet://)?
  • Какие ограничения вы хотите наложить на содержание URL (допустимы ли вредоносные URL)?
3 голосов
/ 15 октября 2008

Просто HTMLE закодировать ссылки, когда вы выводите их. Убедитесь, что вы не разрешаете javascript: ссылки. (Лучше всего иметь белый список принятых протоколов, например, http, https и mailto.)

3 голосов
/ 15 октября 2008

Вы не указываете язык своего приложения, тогда я предполагаю ASP.NET, и для этого вы можете использовать Microsoft Anti-Cross Site Scripting Library

Он очень прост в использовании, все, что вам нужно, это включить, и это все:)

Пока вы обсуждаете эту тему, почему бы не прочитать Рекомендации по разработке безопасных веб-приложений

Если какой-либо другой язык .... если есть библиотека для ASP.NET, должен быть доступен также для других языков (PHP, Python, ROR и т. Д.)

1 голос
/ 15 октября 2008

Как насчет того, чтобы не отображать их как ссылку? Просто используйте текст.

В сочетании с предупреждением действовать на свой страх и риск может быть достаточно.

сложение - см. Также Стоит ли дезинфицировать разметку HTML для размещенной CMS? для обсуждения по санации ввода пользователя

0 голосов
/ 17 марта 2019

Для Pythonistas попробуйте Scrapy's w3lib .

OWASP ESAPI предшествует Python 2.7 и архивируется в несуществующем Google Code .

0 голосов
/ 14 октября 2018

В моем проекте, написанном на JavaScript, я использую это регулярное выражение в виде белого списка:

 url.match(/^((https?|ftp):\/\/|\.{0,2}\/)/)

единственное ограничение заключается в том, что вам нужно поместить ./ для файлов в том же каталоге, но я думаю, что смогу с этим справиться.

0 голосов
/ 26 июля 2013

Вы можете использовать шестнадцатеричный код, чтобы преобразовать весь URL и отправить его на ваш сервер. Таким образом, клиент не будет понимать содержание на первый взгляд. После прочтения контента, вы можете декодировать контент URL =? и отправьте его в браузер.

0 голосов
/ 15 октября 2008

Разрешение URL и JavaScript - это две разные вещи.

...