NextJS

Tip

Učite i vežbajte AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Učite i vežbajte GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Učite i vežbajte Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Podržite HackTricks

Opšta arhitektura Next.js aplikacije

Tipična struktura fajlova

Standardni Next.js projekat prati specifičnu strukturu fajlova i direktorijuma koja olakšava njegove funkcionalnosti kao što su rutiranje, API endpointi i upravljanje statičkim resursima. Evo tipičnog rasporeda:

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

Osnovni direktorijumi i fajlovi

  • public/: Sadrži statičke resurse kao što su slike, fontovi i ostali fajlovi. Fajlovi ovde su dostupni na korenskoj putanji (/).
  • app/: Centralni direktorijum za stranice, layout-e, komponente i API rute vaše aplikacije. Usvaja App Router paradigmu, omogućavajući napredne funkcije rutiranja i razdvajanje server- i klijent-komponenti.
  • app/layout.tsx: Definiše korenski layout vaše aplikacije, obuhvatajući sve stranice i pružajući konzistentne UI elemente kao što su zaglavlja, podnožja i navigacione trake.
  • app/page.tsx: Služi kao ulazna tačka za korensku rutu /, renderujući početnu stranicu.
  • app/[route]/page.tsx: Rukuje statičkim i dinamičkim rutama. Svaka fascikla unutar app/ predstavlja segment rute, a page.tsx unutar te fascikle odgovara komponenti te rute.
  • app/api/: Sadrži API rute, omogućavajući vam da kreirate serverless funkcije koje obrađuju HTTP zahteve. Ove rute zamenjuju tradicionalni direktorijum pages/api.
  • app/components/: Smešta ponovno upotrebljive React komponente koje se mogu koristiti na različitim stranicama i layout-ima.
  • app/styles/: Sadrži globalne CSS fajlove i CSS Modules za stilizaciju ograničenu na komponente.
  • app/utils/: Uključuje utilitarne funkcije, pomoćne module i drugu logiku van UI-a koja se može deliti kroz aplikaciju.
  • .env.local: Čuva environment promenljive specifične za lokalno razvojno okruženje. Ove promenljive se ne čuvaju u verzionoj kontroli.
  • next.config.js: Prilagođava ponašanje Next.js-a, uključujući webpack konfiguracije, environment promenljive i bezbednosna podešavanja.
  • tsconfig.json: Konfiguriše TypeScript podešavanja za projekat, omogućavajući provere tipova i druge TypeScript funkcionalnosti.
  • package.json: Upravljа zavisnostima projekta, skriptama i metapodacima.
  • README.md: Pruža dokumentaciju i informacije o projektu, uključujući uputstva za podešavanje, smernice korišćenja i druge relevantne detalje.
  • yarn.lock / package-lock.json: Zaključava verzije zavisnosti projekta, osiguravajući konzistentne instalacije u različitim okruženjima.

Klijentska strana u Next.js

Rutiranje zasnovano na fajlovima u direktorijumu app

Direktorijum app je temelj rutiranja u najnovijim verzijama Next.js-a. Koristi fajl-sistem za definisanje ruta, čineći upravljanje rutama intuitivnim i skalabilnim.

Rukovanje korenskom putanjom /

Struktura fajlova:

my-nextjs-app/
├── app/
│   ├── layout.tsx
│   └── page.tsx
├── public/
├── next.config.js
└── ...

Ključne datoteke:

  • app/page.tsx: Obrađuje zahteve na root putanji /.
  • app/layout.tsx: Definiše izgled aplikacije, koji obuhvata sve stranice.

Implementacija:

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>
);
}

Objašnjenje:

  • Definicija rute: Fajl page.tsx koji se nalazi direktno u direktorijumu app odgovara ruti /.
  • Renderovanje: Ova komponenta renderuje sadržaj početne strane.
  • Integracija layout-a: Komponenta HomePage je obuhvaćena fajlom layout.tsx, koji može sadržavati zaglavlja, podnožja i druge zajedničke elemente.
Rukovanje drugim statičkim putanjama

Primer: ruta /about

Struktura fajlova:

arduinoCopy codemy-nextjs-app/
├── app/
│   ├── about/
│   │   └── page.tsx
│   ├── layout.tsx
│   └── page.tsx
├── public/
├── next.config.js
└── ...

Implementacija:

// app/about/page.tsx

export default function AboutPage() {
return (
<div>
<h1>About Us</h1>
<p>Learn more about our mission and values.</p>
</div>
)
}

Objašnjenje:

  • Definicija rute: Fajl page.tsx unutar direktorijuma about odgovara ruti /about.
  • Renderovanje: Ova komponenta prikazuje sadržaj za stranicu about.
Dinamičke rute

Dinamičke rute omogućavaju rukovanje putanjama sa promenljivim segmentima, što aplikacijama omogućava prikaz sadržaja na osnovu parametara kao što su ID-ovi, slugovi itd.

Primer: /posts/[id] ruta

Struktura fajlova:

arduinoCopy codemy-nextjs-app/
├── app/
│   ├── posts/
│   │   └── [id]/
│   │       └── page.tsx
│   ├── layout.tsx
│   └── page.tsx
├── public/
├── next.config.js
└── ...

Implementacija:

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>
);
}

Objašnjenje:

  • Dinamički segment: [id] označava dinamički segment u ruti, hvatajući id parametar iz URL-a.
  • Pristup parametrima: Objekat params sadrži dinamičke parametre, dostupne unutar komponente.
  • Poklapanje ruta: Bilo koja putanja koja odgovara /posts/*, kao što su /posts/1, /posts/abc, itd., biće obrađena ovom komponentom.
Ugnježdene rute

Next.js podržava ugnježdeno rutiranje, omogućavajući hijerarhijske strukture ruta koje odražavaju raspored direktorijuma.

Primer: ruta /dashboard/settings/profile

Struktura fajlova:

arduinoCopy codemy-nextjs-app/
├── app/
│   ├── dashboard/
│   │   ├── settings/
│   │   │   └── profile/
│   │   │       └── page.tsx
│   │   └── page.tsx
│   ├── layout.tsx
│   └── page.tsx
├── public/
├── next.config.js
└── ...

Implementacija:

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>
);
}

Objašnjenje:

  • Duboko ugnježđavanje: page.tsx fajl unutar dashboard/settings/profile/ odgovara ruti /dashboard/settings/profile.
  • Odzrcaljavanje hijerarhije: Struktura direktorijuma reflektuje URL putanju, poboljšavajući održavanje i jasnoću.
Catch-All rute

Catch-all rute obrađuju više ugnježdenih segmenata ili nepoznate putanje, pružajući fleksibilnost u rukovanju rutama.

Primer: /* ruta

Struktura fajlova:

my-nextjs-app/
├── app/
│   ├── [...slug]/
│   │   └── page.tsx
│   ├── layout.tsx
│   └── page.tsx
├── public/
├── next.config.js
└── ...

Implementacija:

// 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>
)
}

Objašnjenje:

  • Catch-All Segment: [...slug] hvata sve preostale segmente puta kao niz.
  • Usage: Korisno za rukovanje dinamičkim rutiranjem, npr. putanjama koje kreiraju korisnici, ugnježdenim kategorijama itd.
  • Route Matching: Putanje poput /anything/here, /foo/bar/baz itd. obrađuje ova komponenta.

Potencijalne ranjivosti na strani klijenta

Iako Next.js pruža sigurnu osnovu, nepravilne prakse kodiranja mogu uvesti ranjivosti. Ključne ranjivosti na strani klijenta uključuju:

Cross-Site Scripting (XSS)

XSS napadi se dešavaju kada se zlonamerni skripti ubace u pouzdane veb-sajtove. Napadači mogu izvršavati skripte u pretraživačima korisnika, kradući podatke ili izvršavajući radnje u ime korisnika.

Primer ranjivog koda:

// Dangerous: Injecting user input directly into HTML
function Comment({ userInput }) {
return <div dangerouslySetInnerHTML={{ __html: userInput }} />
}

Zašto je ranjivo: Korišćenje dangerouslySetInnerHTML sa nepouzdanim ulazom omogućava napadačima da ubace maliciozne skripte.

Client-Side Template Injection

Dogodi se kada se korisnički unosi neispravno obrađuju u šablonima, što omogućava napadačima da ubace i izvrše šablone ili izraze.

Primer ranjivog koda:

import React from "react"
import ejs from "ejs"

function RenderTemplate({ template, data }) {
const html = ejs.render(template, data)
return <div dangerouslySetInnerHTML={{ __html: html }} />
}

Zašto je ranjivo: Ako template ili data sadrže zlonamerni sadržaj, to može dovesti do izvršavanja nepredviđenog koda.

Client Path Traversal

Ovo je ranjivost koja napadačima omogućava manipulaciju client-side putanjama kako bi izvršili nepredviđene radnje, kao što je Cross-Site Request Forgery (CSRF). Za razliku od server-side path traversal, koja cilja filesystem servera, CSPT se fokusira na iskorišćavanje mehanizama na client-side kako bi preusmerila legitimne API zahteve na zlonamerne endpoint-e.

Primer ranjivog koda:

Next.js aplikacija omogućava korisnicima da otpremaju i preuzimaju fajlove. Funkcija za preuzimanje je implementirana na client-side, gde korisnici mogu navesti putanju fajla za preuzimanje.

// 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>
)
}

Scenarij napada

  1. Cilj napadača: Izvesti CSRF napad kako bi obrisao kritičnu datoteku (npr., admin/config.json) manipulišući filePath.
  2. Iskorišćavanje CSPT:
  • Zlonamerni unos: Napadač kreira URL sa manipulisanim filePath kao na primer ../deleteFile/config.json.
  • Rezultujući API poziv: Kod na klijentskoj strani šalje zahtev na /api/files/../deleteFile/config.json.
  • Rukovanje na serveru: Ako server ne validira filePath, obradiće zahtev, što može dovesti do brisanja ili otkrivanja osetljivih fajlova.
  1. Izvođenje CSRF-a:
  • Kreirani link: Napadač šalje žrtvi link ili ubacuje zlonamerni skript koji pokreće zahtev za preuzimanje sa manipulisanim filePath.
  • Ishod: Žrtva nenamerno izvršava akciju, što dovodi do neautorizovanog pristupa fajlovima ili njihovog brisanja.

Zašto je ranjivo

  • Nedostatak validacije unosa: Klijentska strana dozvoljava proizvoljne filePath unose, omogućavajući path traversal.
  • Poveravanje unosima sa klijentske strane: API na serverskoj strani veruje i procesuira filePath bez sanitizacije.
  • Potencijalne akcije API-ja: Ako API endpoint izvršava izmene stanja (npr., brisanje, izmena fajlova), može biti iskorišćen putem CSPT.

Serverska strana u Next.js

Server-Side Rendering (SSR)

Stranice se renderuju na serveru pri svakom zahtevu, što obezbeđuje da korisnik dobije potpuno renderovan HTML. U tom slučaju treba da napravite sopstveni prilagođeni server da obrađuje zahteve.

Slučajevi upotrebe:

  • Dinamički sadržaj koji se često menja.
  • SEO optimizacija, jer pretraživači mogu indeksirati potpuno renderovanu stranicu.

Implementacija:

// 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

Generisanje statičkog sajta (SSG)

Stranice se prerenderuju tokom build procesa, što rezultuje bržim učitavanjem i smanjenim opterećenjem servera.

Slučajevi upotrebe:

  • Sadržaj koji se ne menja često.
  • Blogovi, dokumentacija, marketinške stranice.

Implementacija:

// 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

Serverless funkcije (API Routes)

Next.js omogućava kreiranje API endpoint-a kao serverless funkcija. Ove funkcije se izvršavaju po potrebi bez potrebe za dedikovanim serverom.

Upotrebe:

  • Rukovanje slanjem formi.
  • Interakcija sa bazama podataka.
  • Obrada podataka ili integracija sa API-ima trećih strana.

Implementacija:

Uvođenjem app direktorijuma u Next.js 13, routing i rukovanje API-jem su postali fleksibilniji i moćniji. Ovaj moderan pristup se dobro uklapa sa sistemom rutiranja zasnovanim na fajlovima, ali uvodi poboljšane mogućnosti, uključujući podršku za server i client komponente.

Osnovni handler rute

Struktura fajlova:

my-nextjs-app/
├── app/
│   └── api/
│       └── hello/
│           └── route.js
├── package.json
└── ...

Implementacija:

// 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))

Objašnjenje:

  • Lokacija: API routes se nalaze u direktorijumu app/api/.
  • Naziv fajla: Svaki API endpoint se nalazi u svom folderu koji sadrži route.js ili route.ts fajl.
  • Exported Functions: Umesto jednog default export-a, eksportuju se specifične HTTP method funkcije (npr. GET, POST).
  • Rukovanje odgovorima: Koristite Response constructor za vraćanje odgovora, što omogućava veću kontrolu nad headers i status codes.

Kako rukovati drugim putanjama i metodama:

Rukovanje specifičnim HTTP metodama

Next.js 13+ omogućava da definišete handlere za specifične HTTP metode u istom route.js ili route.ts fajlu, što doprinosi jasnijem i organizovanijem kodu.

Primer:

// 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" },
})
}

Objašnjenje:

  • Višestruki eksporti: Svaka HTTP metoda (GET, PUT, DELETE) ima svoju eksportovanu funkciju.
  • Parametri: Drugi argument omogućava pristup parametrima rute preko params.
  • Poboljšani odgovori: Veća kontrola nad response objektima, omogućavajući precizno upravljanje header-ima i status kodovima.
Catch-All i ugnježdene rute

Next.js 13+ podržava napredne opcije rutiranja kao što su catch-all rute i ugnježdene API rute, što omogućava dinamičnije i skalabilnije API strukture.

Primer catch-all rute:

// 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" },
})
}

Objašnjenje:

  • Sintaksa: [...] označava catch-all segment, koji obuhvata sve ugnježdene putanje.
  • Upotreba: Korisno za API-je koji treba da obrađuju rute različite dubine ili dinamičke segmente.

Primer ugnježdenih ruta:

// 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" },
}
)
}

Objašnjenje:

  • Duboko ugnježđavanje: Omogućava hijerarhijske API strukture koje odražavaju odnose između resursa.
  • Pristup parametrima: Lako pristupite višestrukim parametrima rute preko params objekta.
Rukovanje API rutama u Next.js 12 i ranijim verzijama

API rute u direktorijumu pages (Next.js 12 i ranijim verzijama)

Pre nego što je Next.js 13 uveo direktorijum app i poboljšane mogućnosti rutiranja, API rute su se pretežno definisale unutar direktorijuma pages. Ovaj pristup je i dalje široko korišćen i podržan u Next.js 12 i ranijim verzijama.

Osnovna API ruta

Struktura fajlova:

goCopy codemy-nextjs-app/
├── pages/
│   └── api/
│       └── hello.js
├── package.json
└── ...

Implementacija:

javascriptCopy code// pages/api/hello.js

export default function handler(req, res) {
res.status(200).json({ message: 'Hello, World!' });
}

Objašnjenje:

  • Lokacija: API routes se nalaze u direktorijumu pages/api/.
  • Export: Koristite export default da definišete handler funkciju.
  • Potpis funkcije: Handler prima req (HTTP request) i res (HTTP response) objekte.
  • Rutiranje: Ime fajla (hello.js) mapira na endpoint /api/hello.

Dinamičke API rute

Struktura fajlova:

bashCopy codemy-nextjs-app/
├── pages/
│   └── api/
│       └── users/
│           └── [id].js
├── package.json
└── ...

Implementacija:

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`);
}
}

Objašnjenje:

  • Dinamički segmenti: Uglaste zagrade ([id].js) označavaju dinamičke segmente rute.
  • Pristup parametrima: Koristite req.query.id da pristupite dinamičkom parametru.
  • Rukovanje metodama: Koristite uslovnu logiku za rukovanje različitim HTTP metodama (GET, PUT, DELETE, itd.).

Rukovanje različitim HTTP metodama

Iako osnovni primer API rute obrađuje sve HTTP metode unutar jedne funkcije, možete strukturisati svoj kod tako da eksplicitno obrađuje svaku metodu radi bolje preglednosti i održavanja.

Primer:

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`);
}
}

Najbolje prakse:

  • Separation of Concerns: Jasno razdvojite logiku za različite HTTP metode.
  • Response Consistency: Obezbedite konzistentne strukture odgovora radi lakšeg rukovanja na strani klijenta.
  • Error Handling: Na odgovarajući način obradite nepodržane metode i neočekivane greške.

Konfiguracija CORS-a

Kontrolišite koje origin-e mogu pristupiti vašim API rutama, čime se ublažavaju ranjivosti vezane za Cross-Origin Resource Sharing (CORS) vulnerabilities.

Loš primer konfiguracije:

// 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",
},
})
}

Imajte na umu da se CORS može takođe konfigurisati u svim API rutama unutar fajla 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
}

Problem:

  • Access-Control-Allow-Origin: '*': Dozvoljava bilo kojem veb-sajtu da pristupi API-ju, potencijalno omogućavajući zlonamernim sajtovima da komuniciraju sa vašim API-jem bez ograničenja.
  • Široka dozvola metoda: Dozvoljavanje svih metoda može omogućiti napadačima da izvrše neželjene akcije.

Kako napadači to iskorišćavaju:

Napadači mogu napraviti zlonamerne veb-sajtove koji šalju zahteve vašem API-ju, potencijalno zloupotrebljavajući funkcionalnosti kao što su preuzimanje podataka, manipulacija podacima ili pokretanje neželjenih akcija u ime autentifikovanih korisnika.

CORS - Misconfigurations & Bypass

Izlaganje server koda na klijentskoj strani

Lako je koristiti kod koji se koristi na serveru i takođe ga izložiti i koristiti na klijentskoj strani, najbolji način da se osigura da se fajl koda nikada ne izlaže na klijentskoj strani je korišćenjem ovog import na početku fajla:

import "server-only"

Ključne datoteke i njihove uloge

middleware.ts / middleware.js

Location: Root projekta ili unutar src/.

Purpose: Izvršava kod u server-side serverless funkciji pre nego što se zahtev obradi, omogućavajući zadatke kao što su autentikacija, preusmeravanja ili izmena odgovora.

Execution Flow:

  1. Dolazeći zahtev: Middleware presreće zahtev.
  2. Obrada: Izvodi operacije na osnovu zahteva (npr. provera autentikacije).
  3. Izmena odgovora: Može izmeniti odgovor ili predati kontrolu sledećem handleru.

Example Use Cases:

  • Preusmeravanje neautentifikovanih korisnika.
  • Dodavanje prilagođenih zaglavlja.
  • Logovanje zahteva.

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*"],
}

next.config.js

Lokacija: koren projekta.

Svrha: Konfiguriše ponašanje Next.js-a, omogućava ili onemogućava funkcije, prilagođava webpack konfiguracije, postavlja promenljive okruženja i podešava više bezbednosnih opcija.

Ključne bezbednosne konfiguracije:

Bezbednosna zaglavlja

Bezbednosna zaglavlja povećavaju sigurnost vaše aplikacije tako što pregledačima govore kako da tretiraju sadržaj. Pomažu u ublažavanju različitih napada kao što su Cross-Site Scripting (XSS), Clickjacking i MIME type sniffing:

  • Content Security Policy (CSP)
  • X-Frame-Options
  • X-Content-Type-Options
  • Strict-Transport-Security (HSTS)
  • Referrer Policy

Primeri:

// 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...
],
},
]
},
}
Podešavanja optimizacije slika

Next.js optimizuje slike radi performansi, ali pogrešna konfiguracija može dovesti do bezbednosnih ranjivosti, kao što je omogućavanje nepouzdanim izvorima da ubace zlonamerni sadržaj.

Loš primer konfiguracije:

// next.config.js

module.exports = {
images: {
domains: ["*"], // Allows images from any domain
},
}

Problem:

  • '*': Dozvoljava učitavanje slika sa bilo kog eksternog izvora, uključujući nepouzdane ili zlonamerne domene. Napadači mogu hostovati slike koje sadrže zlonamerni payload ili sadržaj koji obmanjuje korisnike.
  • Drugi problem može biti dozvoljavanje domena gde svako može da postavi sliku (npr. raw.githubusercontent.com)

Kako napadači to zloupotrebljavaju:

Ubacivanjem slika sa zlonamernih izvora, napadači mogu izvoditi phishing napade, prikazivati obmanjujuće informacije ili iskorišćavati ranjivosti u bibliotekama za renderovanje slika.

Izlaganje varijabli okruženja

Rukujte osetljivim informacijama poput API ključeva i kredencijala za bazu podataka na siguran način, bez izlaganja klijentu.

a. Izlaganje osetljivih varijabli

Loš primer konfiguracije:

// next.config.js

module.exports = {
env: {
SECRET_API_KEY: process.env.SECRET_API_KEY, // Exposed to the client
NEXT_PUBLIC_API_URL: process.env.NEXT_PUBLIC_API_URL, // Correctly prefixed for client
},
}

Problem:

  • SECRET_API_KEY: Bez prefiksa NEXT_PUBLIC_, Next.js ne izlaže promenljive klijentu. Međutim, ako se greškom doda prefiks (npr. NEXT_PUBLIC_SECRET_API_KEY), one postaju dostupne na strani klijenta.

Kako napadači to zloupotrebljavaju:

Ako su osetljive promenljive izložene klijentu, napadači ih mogu pribaviti pregledom koda na strani klijenta ili mrežnih zahteva, stičući neovlašćen pristup API-jevima, bazama podataka ili drugim servisima.

Preusmeravanja

Upravljajte URL preusmerenjima i prepisivanjima (rewrites) u okviru vaše aplikacije, kako biste osigurali da su korisnici pravilno preusmereni bez uvođenja open redirect vulnerabilities.

a. Open Redirect Vulnerability

Loš primer konfiguracije:

// next.config.js

module.exports = {
async redirects() {
return [
{
source: "/redirect",
destination: (req) => req.query.url, // Dynamically redirects based on query parameter
permanent: false,
},
]
},
}

Problem:

  • Dinamička destinacija: Omogućava korisnicima da navedu bilo koji URL, što omogućava open redirect napade.
  • Pouzdanje u korisničkom unosu: Preusmeravanja na URL-ove koje korisnici navedu bez validacije mogu dovesti do phishing, malware distribution ili credential theft.

How attackers abuse it:

Napadači mogu konstruisati URL-ove koji izgledaju kao da potiču iz vašeg domena, ali preusmeravaju korisnike na zlonamerne sajtove. Na primer:

https://yourdomain.com/redirect?url=https://malicious-site.com

Users trusting the original domain might unknowingly navigate to harmful websites.

Konfiguracija Webpack-a

Prilagođavanje Webpack konfiguracija za vašu Next.js aplikaciju može nenamerno uvesti bezbednosne ranjivosti ako se ne postupa pažljivo.

a. Izlaganje osetljivih modula

Loš primer konfiguracije:

// next.config.js

module.exports = {
webpack: (config, { isServer }) => {
if (!isServer) {
config.resolve.alias["@sensitive"] = path.join(__dirname, "secret-folder")
}
return config
},
}

Problem:

  • Exposing Sensitive Paths: Aliasovanje osetljivih direktorijuma i dozvoljavanje client-side pristupa može leak poverljive informacije.
  • Bundling Secrets: Ako se osetljivi fajlovi bundluju za klijenta, njihov sadržaj postaje dostupan kroz source maps ili pregledom client-side koda.

How attackers abuse it:

Napadači mogu pristupiti ili rekonstruisati strukturu direktorijuma aplikacije, potencijalno pronalazeći i iskorišćavajući osetljive fajlove ili podatke.

pages/_app.js i pages/_document.js

pages/_app.js

Svrha: Preklapa podrazumevanu App komponentu, omogućavajući globalno stanje, stilove i komponente za layout.

Primeri upotrebe:

  • Ubacivanje globalnog CSS-a.
  • Dodavanje wrapper-a za layout.
  • Integracija biblioteka za upravljanje stanjem.

Primer:

// pages/_app.js
import "../styles/globals.css"

function MyApp({ Component, pageProps }) {
return <Component {...pageProps} />
}

export default MyApp

pages/_document.js

Svrha: Zamenjuje podrazumevani Document, omogućavajući prilagođavanje <html> i <body> tagova.

Primeri upotrebe:

  • Izmena <html> ili <body> tagova.
  • Dodavanje meta tagova ili prilagođenih skripti.
  • Integracija fontova trećih strana.

Primer:

// 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

Custom Server (Optional)

Purpose: Dok Next.js dolazi sa built-in serverom, možete kreirati custom server za napredne slučajeve upotrebe kao što su custom routing ili integracija sa postojećim backend services.

Note: Korišćenje custom server-a može ograničiti deployment options, posebno na platformama kao što je Vercel koje su optimizovane za Next.js’s built-in server.

Example:

// 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")
})
})

Dodatna arhitektonska i bezbednosna razmatranja

Varijable okruženja i konfiguracija

Svrha: Upravljanje osetljivim informacijama i podešavanjima konfiguracije izvan codebase-a.

Najbolje prakse:

  • Koristite .env fajlove: Čuvajte varijable kao API keys u .env.local (isključeno iz kontrole verzija).
  • Pristupajte varijablama sigurno: Koristite process.env.VARIABLE_NAME za pristup varijablama okruženja.
  • Nikada ne izlažite tajne na klijentu: Osigurajte da se osetljive varijable koriste samo na serverskoj strani.

Primer:

// 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
},
}

Napomena: Da biste ograničili promenljive samo na serverskoj strani, izostavite ih iz env objekta ili ih prefiksirajte sa NEXT_PUBLIC_ za izlaganje klijentu.

Autentikacija i autorizacija

Pristup:

  • Session-Based Authentication: Koristite cookies za upravljanje korisničkim sesijama.
  • Token-Based Authentication: Implementujte JWTs za autentikaciju bez stanja.
  • Third-Party Providers: Povežite se sa OAuth provajderima (npr., Google, GitHub) koristeći biblioteke kao next-auth.

Bezbednosne prakse:

  • Secure Cookies: Postavite atribute HttpOnly, Secure i SameSite.
  • Password Hashing: Uvek heširajte lozinke pre nego što ih sačuvate.
  • Input Validation: Sprečite injection napade validacijom i sanitizacijom ulaza.

Primer:

// 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" })
}
}

Optimizacija performansi

Strategije:

  • Optimizacija slika: Koristite Next.js-ov next/image komponentu za automatsku optimizaciju slika.
  • Razdvajanje koda: Iskoristite dynamic imports za razdvajanje koda i smanjenje vremena početnog učitavanja.
  • Keširanje: Implementirajte strategije keširanja za API odgovore i statičke resurse.
  • Odloženo učitavanje: Učitajte komponente ili resurse samo kada su potrebni.

Primer:

// Dynamic Import with Code Splitting
import dynamic from "next/dynamic"

const HeavyComponent = dynamic(() => import("../components/HeavyComponent"), {
loading: () => <p>Loading...</p>,
})

Next.js Server Actions Enumeracija (hash u ime funkcije pomoću source maps)

Modern Next.js koristi “Server Actions” koje se izvršavaju na serveru, ali se pozivaju sa klijenta. U produkciji su ti pozivi neprozirni: svi POSTs idu na zajednički endpoint i razlikuju se po hash-u specifičnom za build koji se šalje u Next-Action header. Primer:

POST /
Next-Action: a9f8e2b4c7d1...

Kada je omogućeno productionBrowserSourceMaps, minified JS chunks sadrže pozive createServerReference(...) koji leak-uju dovoljno strukture (plus associated source maps) da se može rekonstruisati mapiranje između action heša i originalnog imena funkcije. Ovo vam omogućava da prevedete heševe primećene u Next-Action u konkretne mete kao što su deleteUserAccount() ili exportFinancialData().

Pristup ekstrakciji (regex on minified JS + optional source maps)

Pretražite preuzete JS chunks za createServerReference i izvucite heš i simbol funkcije/izvora. Dva korisna obrasca:

# 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*\)
  • Grupa 1: server action hash (40+ hex chars)
  • Grupa 2: symbol or path that can be resolved to the original function via the source map when present

If the script advertises a source map (trailer comment //# sourceMappingURL=<...>.map), fetch it and resolve the symbol/path to the original function name.

Praktični tok rada

  • Passive discovery while browsing: capture requests with Next-Action headers and JS chunk URLs.
  • Fetch the referenced JS bundles and accompanying *.map files (when present).
  • Run the regex above to build a hash↔name dictionary.
  • Use the dictionary to target testing:
    • Name-driven triage (e.g., transferFunds, exportFinancialData).
    • Track coverage across builds by function name (hashes rotate across builds).

Vežbanje skrivenih akcija (template-based request)

Uzmite validan POST primećen in-proxy kao šablon i zamenite Next-Action vrednost da ciljate drugu otkrivenu akciju:

# Before
Next-Action: a9f8e2b4c7d1

# After
Next-Action: b7e3f9a2d8c5

Reproduce in Repeater and test authorization, input validation and business logic of otherwise unreachable actions.

Burp automation

  • NextjsServerActionAnalyzer (Burp extension) automatizuje gore navedeno u Burp-u:
  • Pretražuje proxy istoriju za JS chunk-ove, ekstrahuje createServerReference(...) unose i parsira source map-ove kada su dostupni.
  • Održava pretražljivu hash↔function-name rečnik i uklanja duplikate između build-ova po imenu funkcije.
  • Može locirati validan template POST i otvoriti spreman Repeater tab za slanje sa hash-om ciljne akcije zamenjenim.
  • Repo: https://github.com/Adversis/NextjsServerActionAnalyzer

Notes and limitations

  • Zahteva productionBrowserSourceMaps uključen u production okruženju da bi se povratila imena iz bundle-ova/source map-ova.
  • Otkrivanje imena funkcije samo po sebi nije ranjivost; koristite ga za usmeravanje otkrivanja i testiranje autorizacije svake akcije.

React Server Components Flight protocol deserialization RCE (CVE-2025-55182)

Next.js App Router deploymenti koji izlažu Server Actions na react-server-dom-webpack 19.0.0–19.2.0 (Next.js 15.x/16.x) sadrže kritičnu server-side prototype pollution tokom deserializacije Flight chunk-ova. Kroz kreiranje $ referenci unutar Flight payload-a, napadač može od zagađenih prototipova preći na proizvoljno izvršavanje JavaScript-a, a potom i izvršavanje OS komandi unutar Node.js procesa.

NodeJS - proto & prototype Pollution

Attack chain in Flight chunks

  1. Prototype pollution primitive: Set "then": "$1:__proto__:then" so that the resolver writes a then function on Object.prototype. Any plain object processed afterwards becomes a thenable, letting the attacker influence async control flow inside RSC internals.
  2. Rebinding to the global Function constructor: Point _response._formData.get at "$1:constructor:constructor". During resolution, object.constructorObject, and Object.constructorFunction, so future calls to _formData.get() actually execute Function(...).
  3. Code execution via _prefix: Place JavaScript source in _response._prefix. When the polluted _formData.get is invoked, the framework evaluates Function(_prefix)(...), so the injected JS can run require('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" }
}
}

Reference

Tip

Učite i vežbajte AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Učite i vežbajte GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Učite i vežbajte Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Podržite HackTricks