двойная escape-последовательность внутри URL: модуль фильтрации запросов настроен на отклонение запроса, который содержит двойную escape-последовательность

86

В моем приложении ASP.NET MVC я пытаюсь реализовать URL-адрес, как показано ниже:

/ product / tags / для + семей

Когда я пытаюсь запустить свое приложение с конфигурациями по умолчанию, я получаю это сообщение с кодом ответа 404.11:

Ошибка HTTP 404.11 - не найдено

Модуль фильтрации запросов настроен на отклонение запроса, содержащего двойную escape-последовательность.

Я могу обойти эту ошибку, реализовав следующий код в моем web.config:

  <system.webServer>
    <security>
      <requestFiltering allowDoubleEscaping="true" />
    </security>
  </system.webServer>

Итак, теперь я ничего не получаю 404.11.

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

Кстати, мое приложение работает .Net Framework 4.0и работает IIS 7.5.

тугберк
источник
Можно ли /product/tags/for%20familiesвместо этого достичь желаемого ресурса ? Тогда у вас есть обходной путь для идентификаторов, содержащих пробелы. Или я совсем здесь?
Андерс Торнблад
@atornblad, я думаю, немного не в себе. Мой вопрос: мне интересно, какие дыры в безопасности я открываю с помощью этой реализации.
tugberk
5
IIS добавляет символ «+», что является поведением Microsoft по умолчанию.
Тодд Шелтон

Ответы:

57

Бреши в безопасности, которые вы можете открыть, связаны с внедрением кода - HTML-инъекцией, JavaScript-инъекцией или SQL-инъекцией.

Настройки по умолчанию защищают вас от атак полуэффективно, не позволяя работать обычным стратегиям внедрения. Чем больше защиты по умолчанию вы удаляете, тем больше вам нужно думать о том, что вы делаете с вводом, предоставленным через URL-адреса, строки запроса GET, данные запроса POST, заголовки HTTP и так далее ...

Например, если вы строите динамические запросы SQL на основе idпараметра вашего метода действия, например:

public ActionResult Tags(string id)
{
    var sql = "SELECT * FROM Tags Where tagName = '" + id + "'";
    // DO STUFF...
}

(... что НЕ является хорошей идеей), защита по умолчанию, установленная .NET framework, может остановить некоторые из наиболее опасных сценариев, например, когда пользователь запрашивает этот URL:

/product/tags/1%27;drop%20table%20Tags;%20--

Вся идея состоит в том, чтобы рассматривать каждую часть URL-адресов и другие входные данные для методов действий как возможные угрозы. Настройка безопасности по умолчанию действительно обеспечивает вам некоторую защиту. Каждый параметр безопасности по умолчанию, который вы изменяете, открывает немного больше потенциальных угроз, с которыми вам нужно справиться вручную.

Я предполагаю, что вы не строите SQL-запросы таким образом. Но более хитрые вещи возникают, когда вы сохраняете вводимые пользователем данные в своей базе данных, а затем отображаете их. Злонамеренный пользователь может хранить в вашей базе данных JavaScript или HTML, которые выходят незашифрованными, что, в свою очередь, может угрожать другим пользователям вашей системы.

Андерс Торнблад
источник
6

Риск безопасности

Этот параметр allowDoubleEscapingприменяется только к path(cs-uri-stem) и лучше всего объясняется двойным кодированием OWASP . Этот метод используется для обхода элементов управления безопасностью путем двойного кодирования запроса URL-адресом. Используя ваш URL в качестве примера:

/product/tags/for+families --> /product/tags/for%2Bfamilies --> /product/tags/for%252Bfamilies

Предположим, есть средства безопасности специально для /product/tags/for+families. Поступает запрос, /product/tags/for%252Bfamiliesкоторый является тем же ресурсом, но не проверяется вышеупомянутыми элементами управления безопасностью. Я использовал общий термин управления безопасностью, потому что они могли быть чем угодно, например требованием аутентифицированного пользователя, проверкой SQLi и т. Д.

Почему IIS блокирует?

Знак плюс (+) является зарезервированным символом согласно RFC2396 :

Многие URI включают компоненты, состоящие из определенных специальных символов или разделенные ими. Эти символы называются «зарезервированными», поскольку их использование в компоненте URI ограничено их зарезервированной целью. Если данные для компонента URI будут конфликтовать с зарезервированной целью, то конфликтующие данные должны быть экранированы перед формированием URI.

  reserved    = ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" |
                "$" | ","

У Уэйда Хилмо есть отличный пост под названием Как IIS блокирует символы в URL-адресах . Предоставляется много информации и предыстории. Часть, специально предназначенная для знака плюса, выглядит следующим образом:

Так что allowDoubleEscaping / VerifyNormalization кажется довольно простым. Почему я сказал, что это вызывает недоумение? Проблема заключается в том, что в URL-адресе появляется символ «+». Кажется, что символ «+» не экранирован, так как в нем нет символа «%». Кроме того, RFC 2396 отмечает его как зарезервированный символ, который может быть включен в URL-адрес в экранированной форме (% 2b). Но если для параметра allowDoubleEscaping установлено значение по умолчанию false, мы заблокируем его даже в экранированной форме. Причина этого историческая: еще в первые дни HTTP символ «+» считался сокращением для символа пробела. Некоторые каноникализаторы, если им дан URL-адрес, содержащий '+', преобразуют его в пробел. По этой причине мы считаем "+" в URL неканоническим. Мне не удалось найти никаких ссылок на RFC, в котором упоминается эта обработка "+",

По собственному опыту знаю, что когда IIS регистрирует запросы, пробелы заменяются знаком плюс. Наличие в имени знака плюса может вызвать путаницу при анализе журналов.

Решение

Есть три способа исправить это и два способа по-прежнему использовать знак плюса.

  1. allowDoubleEscaping=true- Это позволит двойное экранирование для всего вашего сайта / приложения. В зависимости от содержания это может быть, мягко говоря, нежелательно. Будет установлена ​​следующая команда allowDoubleEscaping=true.

    appcmd.exe set config "Default Web Site" -section:system.webServer/security/requestFiltering /allowDoubleEscaping:True
    
  2. alwaysAllowedUrls- Фильтрация запросов предлагает подход с использованием белого списка. Если добавить этот URL-путь в alwaysAllowedUrls, запрос не будет проверяться никакими другими параметрами фильтрации запросов и продолжится в конвейере запросов IIS. Проблема здесь в том, что фильтрация запросов не будет проверять запрос на:

    • Пределы запросов: maxContentLength, maxUrl, maxQueryString
    • Глаголы
    • Запрос - параметры строки запроса проверяться не будут
    • Двойной побег
    • Персонажи с высоким битом
    • Правила фильтрации запросов
    • Ограничения заголовка запроса

    Следующая команда добавит /product/tags/for+familiesк alwaysAllowedUrlsпо умолчанию веб - сайта.

    appcmd.exe set config "Default Web Site" -section:system.webServer/security/requestFiltering /+"alwaysAllowedUrls.[url='/product/tags/for+families']"
    
  3. Переименовать - да, просто переименовать файл / папку / контроллер / и т.д. если возможно. Это самое простое решение.

user2320464
источник
Чтобы разрешить DoubleEscaping во время разработки с IIS Express, вот что я сделал: stackoverflow.com/q/56463044/381082
DeveloperDan
3

Я сделал для этого работу. поэтому, когда вы хотите поместить зашифрованную строку в URL-адрес для (IIS), вы должны очистить ее от грязных: {";", "/", "?", ":", "@", "&", " = "," + "," $ ",", "}; и когда вы хотите расшифровать его и использовать снова, вы должны снова сделать его грязным, прежде чем расшифровывать его (чтобы получить желаемый результат).

Вот мой код, надеюсь, он кому-то поможет:

 public static string cleanUpEncription(string encriptedstring)
        {
            string[] dirtyCharacters = { ";", "/", "?", ":", "@", "&", "=", "+", "$", "," };
            string[] cleanCharacters = { "p2n3t4G5l6m","s1l2a3s4h","q1e2st3i4o5n" ,"T22p14nt2s", "a9t" , "a2n3nd","e1q2ua88l","p22l33u1ws","d0l1ar5","c0m8a1a"};

            foreach (string dirtyCharacter in dirtyCharacters)
            {
                encriptedstring=encriptedstring.Replace(dirtyCharacter, cleanCharacters[Array.IndexOf(dirtyCharacters, dirtyCharacter)]);
            }
            return encriptedstring;
        }

        public static string MakeItDirtyAgain(string encriptedString)
        {
            string[] dirtyCharacters = { ";", "/", "?", ":", "@", "&", "=", "+", "$", "," };
            string[] cleanCharacters = { "p2n3t4G5l6m", "s1l2a3s4h", "q1e2st3i4o5n", "T22p14nt2s", "a9t", "a2n3nd", "e1q2ua88l", "p22l33u1ws", "d0l1ar5", "c0m8a1a" };
            foreach (string symbol in cleanCharacters)
            {
                encriptedString = encriptedString.Replace(symbol, dirtyCharacters[Array.IndexOf(cleanCharacters,symbol)]);
            }
            return encriptedString;
        }
Марк Дибех
источник
Что такое pntGlm?
StuperUser
@StuperUser просто случайные символы
Марк Дибех
1
Строку следует base64кодировать вместо использования этого метода подстановки. Например, обычная проверка подлинности используется base64для кодирования отправленных учетных данных, поскольку они могут содержать специальные / зарезервированные символы.
user2320464
проблема с base64 является / является символом base64 и может нарушить маршруты
Гарр Годфри,
1

Поэтому я столкнулся с этим, когда вызывал API из приложения MVC. Вместо того, чтобы открыть дыру в безопасности, я изменил свой путь.

Во-первых, я рекомендую НЕ отключать этот параметр. Более целесообразно изменить дизайн приложения / ресурса (например, закодировать путь, передать данные в заголовке или в теле).

Хотя это более старый пост, я подумал, что поделюсь, как вы можете разрешить эту ошибку, если вы получаете ее из вызова API с помощью метода HttpUtility.UrlPathEncode в System.Web .

Я использую RestSharp для выполнения вызовов, поэтому в моем примере используется RestRequest:

var tags = new[] { "for", "family" };
var apiRequest = new RestRequest($"product/tags/{HttpUtility.UrlPathEncode(string.Join("+", tags))}");

Это дает путь, равный:

/ product / tags / для% 2Bfamilies

С другой стороны, НЕ создавайте динамический запрос на основе вводимых пользователем данных. Вы ДОЛЖНЫ всегда использовать SqlParameter . Кроме того, с точки зрения безопасности чрезвычайно важно возвращать значения с соответствующей кодировкой для предотвращения атак путем внедрения.

~ Ура

Рогала
источник
0

Закодируйте зашифрованную строку с разделением:

return HttpServerUtility.UrlTokenEncode(Encoding.UTF8.GetBytes("string"));

Расшифруйте зашифрованную строку, разделенную:

string x = Encoding.UTF8.GetString(HttpServerUtility.UrlTokenDecode(id));
Unvascorriendo
источник