Next.js та вразливість середовища: неефективний механізм авторизації

TechubNews
REACT1,03%

Автор: Rachid.A

Переклад: Yewlne

01 Текст перекладу

Нещодавно ми з Ясіром Алламом, який виступає під псевдонімом inzo_, вирішили об’єднати зусилля для дослідження. Обговоривши кілька потенційних цілей, ми вирішили зосередитися на Next.js (який має 130 000 зірок на GitHub і наразі має понад 9,4 мільйона завантажень на тиждень). Це фреймворк, з яким я добре знайомий, і у мене був чудовий досвід роботи з ним, про що свідчать мої попередні дослідження. Тому «ми» в цій статті, природно, відноситься до нас обох.

Next.js є повнофункціональним JavaScript фреймворком на базі React, що має багатий набір функцій — це ідеальне місце для глибокого дослідження деталей. З вірою, цікавістю та наполегливістю ми вирушаємо в подорож, щоб дослідити маловідомі куточки та знайти приховані в них скарби.

Невдовзі ми виявили серйозну проблему в проміжному програмному забезпеченні. Її вплив є широким, усі версії підпадають під вплив, і для використання цієї уразливості не потрібні жодні попередні умови — ми скоро детально продемонструємо це.

Каталог

Проміжне програмне забезпечення Next.js

Дозвільний артефакт: скарбовий рівень старого коду

Виконання порядку з middlewareInfo.name

Інструмент авторизації: вчора вже став поезією, сьогодні ще більш вартий того

/src каталог

Максимальна глибина рекурсії

експлуатація вразливостей

Оминання авторизації/перезапис

обійти CSP

Здійснення DoS через отруєння кешу (Що?)

прояснення

Оголошення про безпеку - CVE-2025-29927

Відмова від відповідальності

Висновок

Проміжне програмне забезпечення Next.js

Проміжне програмне забезпечення дозволяє виконати код до того, як запит буде завершено. Потім ви можете змінити вміст відповіді, переписавши, перенаправивши, змінивши заголовки запиту чи відповіді, або повернувши відповідь безпосередньо на основі вхідного запиту (витяг із документації Next.js).

Як повноцінна платформа, Next.js має власні посередники (middleware) — це важлива та широко використовувана функція. Її сфери застосування численні, серед яких найважливіші включають:

Переписування шляху (Path rewriting)

Серверні редиректи (Server-side redirects)

Додати заголовкову інформацію до відповіді (наприклад, CSP тощо)

Найважливіше: аутентифікація (Authentication) та авторизація (Authorization)

Звичайним використанням посередника є авторизація, що включає захист певних шляхів на основі специфічних умов.

Перевірка особи та авторизація: перед наданням доступу до певних сторінок або API-маршрутів, переконайтеся в особі користувача та перевірте сесійне Cookie (документація Next.js).

Приклад: коли користувач намагається отримати доступ до /dashboard/admin, запит спочатку проходить через посередника, який перевіряє, чи є сеанс cookie користувача дійсним і чи має він необхідні права. Якщо перевірка пройдена, посередник пересилає запит; інакше, посередник перенаправляє користувача на сторінку входу:

Авторизаційний артефакт: скарбовий рівень старого коду

Як сказав великий чоловік: «розмови нічого не варті, покажи мені помилку», давайте уникнемо зайвих описів і відразу перейдемо до справи; під час перегляду старої версії фреймворку (v12.0.7) ми знайшли цей фрагмент коду:

Коли Next.js-застосунок використовує проміжне програмне забезпечення, викликається функція runMiddleware. На додаток до своєї основної функції, функція приймає значення заголовка x-middleware-subrequest і використовує його для визначення того, чи слід застосовувати проміжне програмне забезпечення. Значення заголовка розбивається на список за допомогою двокрапки (:) як роздільника, і перевіряється, чи містить він значення middlewareInfo.name. Це означає, що якщо ми додамо до запиту заголовок x-middleware-subrequest з правильним значенням, то проміжне програмне забезпечення – незалежно від його призначення – буде повністю проігноровано, а запит буде перенаправлений через NextResponse.next() і шлях до початкового призначення буде завершено без будь-якого впливу проміжного програмного забезпечення. Ця головка і її значення схожі на «відмичку», яка обходить всі правила. На цьому етапі ми зрозуміли, що знайшли дивовижну проблему, і останні кілька частин головоломки потрібно завершити далі.

Щоб наш «універсальний ключ» запрацював, його значення повинно містити middlewareInfo.name, але що ж таке це значення?

Виконання порядку з middlewareInfo.name

Значення middlewareInfo.name дуже легко здогадатися, це просто шлях, де знаходиться проміжне програмне забезпечення. Щоб зрозуміти це, нам потрібно трохи ознайомитися з тим, як налаштовувалося проміжне програмне забезпечення в старих версіях.

По-перше, у версії до 12.2 – в якій відбулася зміна угоди щодо посередників – файли повинні бути названі _middleware.ts. Крім того, маршрутизатор (router) додатка був введений лише у версії 13 Next.js. Єдиним маршрутизатором, який існував на той момент, був маршрутизатор pages, тому цей файл повинен бути розміщений у папці pages (специфічно для маршрутизатора).

Маючи цю інформацію, ми можемо вивести точний шлях проміжного програмного забезпечення і, таким чином, вгадати значення заголовка x-middleware-subrequest. Це значення просто складається з назви каталогу (тобто унікального імені маршрутизатора, яке існує на той момент) та назви файлу, відповідно до правил іменування, які починаються з символу підкреслення:

x-middleware-subrequest: сторінки/_middleware

Коли ми намагаємося обійти ті, хто налаштований систематично перенаправляти спроби доступу з /dashboard/team/admin на /dashboard:

Успішно, ми вторглися ⚔️

Ми тепер можемо повністю обійти проміжне програмне забезпечення, а отже, і будь-які системи захисту, що базуються на ньому, найтиповіше з яких є авторизація, як у нашому наведеному вище прикладі. Це відкриття досить вражаюче, але є й інші моменти, які потрібно врахувати.

Попередні версії 12.2 дозволяли вкладеним маршрутам розміщувати один або кілька _middleware файлів в будь-якому місці дерева каталогів (починаючи з папки pages), і вони виконувалися по порядку, як ми бачимо на скріншотах старих документів, отриманих з Веб-архіву:

Це що означає для нашого використання вразливостей?

Імовірність = Кількість рівнів у шляху

Отже, для доступу до /dashboard/panel/admin (захищеного проміжним програмним забезпеченням) значення middlewareInfo.name може мати три можливості, відповідно значення x-middleware-subrequest також може мати три можливості:

сторінки/_middleware

чи

pages/dashboard/_middleware

або

pages/dashboard/panel/_middleware

Інструмент авторизації: вчора вже став поезією, сьогодні ще більш вартий того

До теперішнього часу ми вважаємо, що тільки версії до 13 легко піддаються атаці, оскільки проміжне програмне забезпечення було переміщено в вихідний код, і ми все ще не охопили всі його аспекти. Ми припускаємо, що розробники, напевно, вже звернули увагу на цей недолік і виправили його перед значними змінами в версії 13, тому ми повідомили розробникам фреймворку про цей недолік і продовжили наше дослідження.

Дуже нас здивувало, що через два дні після первинного виявлення ми виявили, що всі версії Next.js — починаючи з версії 11.1.4 — мають вразливість! Код більше не знаходиться в одному і тому ж місці, логіка експлуатації також дещо змінилася.

Як вже згадувалося, починаючи з версії 12.2, файл більше не містить підкреслень і повинен бути просто названий middleware.ts. Крім того, він більше не знаходиться в папці pages (що для нас зручно, оскільки з версії 13 було введено маршрутизатор додатків, що подвоїло б можливості).

З урахуванням цього, корисне навантаження для перших версій, починаючи з версії 12.2, є дуже простим:

Враховуючи це, перше навантаження починаючи з версії 12.2 є дуже простим:

x-middleware-subrequest: проміжне програмне забезпечення

/src каталог

Слід також врахувати, що Next.js надає можливість створення каталогу /src:

(Next.js documentation) В якості альтернативи наявності спеціального каталогу Next.js app або pages в кореневому каталозі вашого проекту, Next.js також підтримує загальний шаблон розміщення коду вашого додатку в каталозі src. (Next.js док.)

У цьому випадку payload буде:

x-middleware-subrequest: src/middleware

Отже, незалежно від того, скільки рівнів у шляху, існує лише два можливі варіанти. Це спростило складність експлуатації вразливостей для відповідних версій.

У останній версії в ньому знову є невеликі зміни (ми обіцяємо, востаннє).

Максимальна глибина рекурсії

У оновленій версії логіка трохи змінилась, будь ласка, подивіться на цей фрагмент коду:

v15.1.7

Як і раніше, система буде шукати значення заголовка x-middleware-subrequest та використовувати двокрапку як роздільник для формування списку. Але цього разу умови прямої пересилки запиту — тобто ігнорування правил проміжного програмного забезпечення — відрізняються:

Значення константи depth повинно бути більшим або рівним значенню константи MAX_RECURSION_DEPTH (тобто 5). Під час присвоєння, щоразу, коли значення у списку subrequests (тобто значення заголовка, розділені двокрапкою) дорівнює params.name (тобто шляху до посередника), константа depth збільшується на 1. Як вже згадувалося, тут є лише два можливі варіанти: middleware або src/middleware.

Отже, щоб обійти посередника, нам потрібно лише додати наступні заголовки/значення у запит:

x-middleware-subrequest: проміжне програмне забезпечення:проміжне програмне забезпечення:проміжне програмне забезпечення:проміжне програмне забезпечення

або

x-middleware-subrequest: src/middleware:src/middleware:src/middleware:src/middleware:src/middleware:src/middleware

Для чого спочатку був написаний цей код?

Цей код, здається, призначений для запобігання безкінечним циклам рекурсивних запитів.

експлуатація вразливостей

Оскільки ми знаємо, що вам подобається такий контент, ось кілька реальних випадків з програми Bug Bounty.

Оминання авторизації/перезапис

У цьому прикладі, коли ми намагаємося отримати доступ до /admin/login, ми отримуємо відповідь 404. Як видно із заголовків відповідей, проміжне програмне забезпечення виконує переписування шляху, щоб запобігти несанкціонованому або неналежному доступу користувачів:

Але використовуючи наш авторизований артефакт :

Ми можемо безперешкодно отримати доступ до цієї точки, проміжне програмне забезпечення повністю ігнорується. Цільова версія Next.js: 15.1.7

обійти CSP

Цього разу веб-сайт використовує посередницьке програмне забезпечення для налаштування — крім інших функцій — CSP і cookie:

Давайте обійдемо це:

Цільова версія next.js: 15.0.3Цільова версія next.js: 15.0.3

Зверніть увагу: будь ласка, зверніть увагу на різницю в payload двох цілей, один з яких використовує каталог src/, а інший - ні.

Здійснення DoS через отруєння кешу (Що?)

Так, за допомогою цього вразливості також може бути реалізована атака на відмову в обслуговуванні (DoS) шляхом отруєння кешу. Це очевидно не те, що ми першочергово шукаємо, але якщо чутливі шляхи не захищені, і немає більш цікавих точок, які можна експлуатувати, тоді в деяких випадках можливе отруєння кешу для відмови в обслуговуванні (CPDoS):

Припустимо, що веб-сайт переписує шлях користувача відповідно до геолокації, додаючи (/en, /fr тощо), і не надає сторінок або ресурсів на кореневому шляху (/). Якщо ми обійдемо посередника, ми уникнемо переписування і врешті-решт потрапимо на кореневу сторінку. Оскільки розробники не планували дозволяти користувачам отримувати доступ до кореневої сторінки, відповідну сторінку не було надано, тому ми отримаємо 404 (або, залежно від конфігурації/типу переписування, це може бути 500).

Якщо веб-сайт використовує систему кешування/CDN, це може примусово кешувати 404-відповіді, що призводить до недоступності сторінки та серйозно впливає на доступність сайту.

прояснення

З моменту публікації повідомлення про безпеку ми отримали запити від деяких людей, які стурбовані безпекою своїх програм і не зовсім розуміють масштаб атак. Потрібно чітко зазначити, що вразливими елементами є проміжне програмне забезпечення. Якщо ви не використовуєте проміжне програмне забезпечення (або, принаймні, не використовуєте його для чутливих цілей), то не потрібно турбуватися (проте, будь ласка, перевірте згадану вище сторону DoS), оскільки обхід проміжного програмного забезпечення не обходить жодних реальних механізмів безпеки.

Інакше наслідки можуть бути катастрофічними, ми рекомендуємо вам швидко реалізувати рекомендації, наведені в оголошенні про безпеку.

Оголошення про безпеку - CVE-2025-29927

патч

Для Next.js 15.x ця проблема була виправлена в 15.2.3

Для Next.js 14.x ця проблема була виправлена в 14.2.25

Для версій Next.js від 11.1.4 до 13.5.6 ми рекомендуємо ознайомитися з наступними рішеннями.

Рішення

Якщо ви не можете оновити до безпечної версії, ми рекомендуємо вам заблокувати запити зовнішніх користувачів, які містять заголовок запиту x-middleware-subrequest, для доступу до вашого додатку Next.js.

Серйозність

CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N(Серйозність: 9.1/10, критичний рівень)

Більше інформації

На момент написання цієї статті, застосунки, розгорнуті на Vercel та Netlify, очевидно, більше не підлягають впливу цієї вразливості (оновлення: через велику кількість хибних сповіщень Cloudflare змінив це правило, щоб воно діяло лише за умови, що користувач самостійно його активує — ці хибні сповіщення не змогли ефективно розрізнити запити від легітимних користувачів та потенційних зловмисників).

Відмова від відповідальності

Це дослідження публікується виключно в освітніх цілях, з метою допомогти розробникам зрозуміти корінні причини проблеми, або надати натхнення дослідникам / дослідникам вразливостей у їхній майбутній дослідницькій роботі. Ця стаття є додатковим матеріалом до безпекового оголошення, що надає додаткові пояснення та роз’яснення щодо природи вразливості — оскільки в оголошенні вже було оприлюднено заголовки запитів, які призвели до цієї вразливості (а також відповідні відмінності подань).

Ми чітко заявляємо, що не підтримуємо будь-яке неетичне використання цього документа.

Висновок

Як зазначено в цій статті, ця вразливість була у вихідному коді Next.js протягом кількох років, змінюючись у міру розвитку проміжного програмного забезпечення та його версій. Серйозні уразливості можуть виникнути в будь-якому програмному забезпеченні, але це стає особливо небезпечним, коли зачіпає один з найпопулярніших фреймворків, з серйозними наслідками для ширшої екосистеми. Як згадувалося раніше, на момент написання статті Next.js наближається до 10 мільйонів завантажень на тиждень. Він широко використовується в ключових сферах, починаючи від банківських послуг і закінчуючи блокчейном. Ризик стає ще більшим, коли вразливості впливають на зрілі функції, на які покладаються користувачі, такі як авторизація та аутентифікація.

Команда Vercel витратила кілька днів на вирішення цього вразливості, але варто зазначити, що, як тільки вони усвідомили проблему, виправлення було подано та об’єднано в нову версію протягом кількох годин (включаючи зворотну портативність).

Часова лінія :

27 лютого 2025 року: було повідомлено про вразливість розробникам (на той момент ми вважали, що лише версії 12.0.0 до 12.0.7 підпадають під вплив, і це було зазначено в звіті).

1 березня 2025 р.: Було надіслано другий електронний лист із заявою про те, що вразливості є практично у всіх версіях, включаючи останню стабільну версію.

5 березня 2025 року: отримано попередню відповідь від команди Vercel, в якій повідомляється, що версія 12.x більше не підтримується (можливо, ще не прочитали наш шаблон оголошення про безпеку, прикріплений до другого листа, і не звернули уваги на те, що всі версії підпадають під вплив).

5 березня 2025 року: ще раз надішліть електронний лист, будь ласка, команда, якнайшвидше ознайомтеся з другим електронним листом та шаблоном безпекового повідомлення.

11 березня 2025 року: повторно надішліть електронний лист, щоб підтвердити, чи була прийнята нова інформація.

17 березня 2025 року: отримано відповідь від команди Vercel, підтверджено, що відповідну інформацію прийнято.

18 березня 2025 року: отримано електронний лист від команди Vercel, в якому повідомляється, що звіт був прийнятий, а патч для виправлення завершено. Через кілька годин було випущено версію 15.2.3 з виправленнями (і зворотним виправленням).

21 березня 2025 року: офіційно опубліковано оголошення про безпеку.

В цілому, процес пошуку нульових вразливостей стає захоплюючим, лише коли з’являється перша підказка, а адреналін зашкалює; інший час це схоже на подорож, сповнену невизначеності — для допитливих це приносить знання; для тих, хто не має терпіння, ця подорож здається особливо довгою. Не соромтеся, командна робота завжди легша, ніж подорожувати по пустелі наодинці.

Переглянути оригінал
Застереження: Інформація на цій сторінці може походити від третіх осіб і не відображає погляди або думки Gate. Вміст, що відображається на цій сторінці, є лише довідковим і не є фінансовою, інвестиційною або юридичною порадою. Gate не гарантує точність або повноту інформації і не несе відповідальності за будь-які збитки, що виникли в результаті використання цієї інформації. Інвестиції у віртуальні активи пов'язані з високим ризиком і піддаються значній ціновій волатильності. Ви можете втратити весь вкладений капітал. Будь ласка, повністю усвідомлюйте відповідні ризики та приймайте обережні рішення, виходячи з вашого фінансового становища та толерантності до ризику. Для отримання детальної інформації, будь ласка, зверніться до Застереження.
Прокоментувати
0/400
Немає коментарів