подвійна послідовність виходу всередині URL-адреси: Модуль фільтрації запитів налаштований на відмову в запиті, що містить подвійну послідовність переходів


86

У моїй програмі ASP.NET MVC я намагаюся застосувати URL-адресу, як показано нижче:

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

Коли я намагаюся запустити свою програму з конфігураціями за замовчуванням, я отримую це повідомлення з кодом відповіді 404.11:

Помилка HTTP 404.11 - не знайдено

Модуль фільтрації запитів налаштований на заборону запиту, який містить подвійну послідовність екранування.

Я можу обійти цю помилку, реалізувавши наведений нижче код всередині мого 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 трохи відходить, я думаю. Моє запитання: Мені цікаво, що такі отвори в безпеці я відкриваю цим впровадженням.
тугберк

5
IIS використовує символ "+", що є типовою поведінкою Microsoft.
Тодд Шелтон,

Відповіді:


56

Діри в безпеці, які ви можете відкрити, пов’язані з ін’єкцією коду - ін’єкцією 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, може зупинити деякі з найбільш небезпечних сценаріїв, наприклад, користувач, що запитує цю 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. Перейменувати - так, просто перейменуйте файл / папку / контролер / тощо. якщо можливо. Це найпростіше рішення.


Щоб дозволити DoubleEscaping під час розробки за допомогою IIS Express, ось що я зробив: stackoverflow.com/q/56463044/381082
розробник,

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 / для% 2B сімей

З іншого боку, НЕ будуйте динамічний запит на основі даних користувача. ТРЕБА завжди використовувати параметр SqlParameter . Крім того, надзвичайно важливо з точки зору безпеки повертати значення з відповідним кодуванням, щоб запобігти ін'єкційним атакам.

~ На ура


0

Кодуйте зашифрований рядок відокремлено:

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

Розшифруйте зашифрований рядок окремо:

string x = Encoding.UTF8.GetString(HttpServerUtility.UrlTokenDecode(id));
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.