NextJS
Tip
Impara e pratica il hacking AWS:
HackTricks Training AWS Red Team Expert (ARTE)
Impara e pratica il hacking GCP:HackTricks Training GCP Red Team Expert (GRTE)
Impara e pratica il hacking Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Supporta HackTricks
- Controlla i piani di abbonamento!
- Unisciti al đŹ gruppo Discord o al gruppo telegram o seguici su Twitter đŚ @hacktricks_live.
- Condividi trucchi di hacking inviando PR ai HackTricks e HackTricks Cloud repos github.
Architettura generale di unâapplicazione Next.js
Struttura tipica dei file
Un progetto Next.js standard segue una specifica struttura di file e directory che facilita funzionalitĂ come routing, API endpoints e gestione delle risorse statiche. Ecco una disposizione tipica:
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
Directory e file principali
- public/: Ospita asset statici come immagini, font e altri file. I file qui sono accessibili dal percorso root (
/). - app/: Directory centrale per le pagine, i layout, i componenti e le API routes della tua applicazione. Abbraccia il paradigma App Router, abilitando funzionalitĂ avanzate di routing e la segregazione dei componenti server-client.
- app/layout.tsx: Definisce il layout radice della tua applicazione, avvolgendo tutte le pagine e fornendo elementi UI coerenti come header, footer e barre di navigazione.
- app/page.tsx: Serve come punto dâingresso per la route root
/, renderizzando la homepage. - app/[route]/page.tsx: Gestisce route statiche e dinamiche. Ogni cartella allâinterno di
app/rappresenta un segmento di route, e ilpage.tsxin quelle cartelle corrisponde al componente della route. - app/api/: Contiene API routes, permettendoti di creare serverless functions che gestiscono richieste HTTP. Queste route sostituiscono la tradizionale directory
pages/api. - app/components/: Ospita componenti React riutilizzabili che possono essere usati in diverse pagine e layout.
- app/styles/: Contiene file CSS globali e CSS Modules per lo styling a livello di componente.
- app/utils/: Include funzioni utility, moduli helper e altra logica non-UI condivisibile in tutta lâapplicazione.
- .env.local: Memorizza le variabili dâambiente specifiche per lâambiente di sviluppo locale. Queste variabili non vengono commesse al controllo versione.
- next.config.js: Personalizza il comportamento di Next.js, incluse configurazioni webpack, variabili dâambiente e impostazioni di sicurezza.
- tsconfig.json: Configura le impostazioni TypeScript per il progetto, abilitando il type checking e altre funzionalitĂ TypeScript.
- package.json: Gestisce le dipendenze del progetto, gli script e i metadata.
- README.md: Fornisce documentazione e informazioni sul progetto, incluse istruzioni di setup, linee guida dâuso e altri dettagli rilevanti.
- yarn.lock / package-lock.json: Blocca le dipendenze del progetto a versioni specifiche, assicurando installazioni coerenti tra diversi ambienti.
Lato client in Next.js
Routing basato sui file nella directory app
La directory app è la pietra angolare del routing nelle versioni piÚ recenti di Next.js. Sfrutta il filesystem per definire le route, rendendo la gestione delle route intuitiva e scalabile.
Gestire il percorso root /
Struttura dei file:
my-nextjs-app/
âââ app/
â âââ layout.tsx
â âââ page.tsx
âââ public/
âââ next.config.js
âââ ...
File chiave:
app/page.tsx: Gestisce le richieste al percorso root/.app/layout.tsx: Definisce il layout dellâapplicazione, che avvolge tutte le pagine.
Implementazione:
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>
);
}
Spiegazione:
- Definizione della route: Il file
page.tsxdirettamente sotto la directoryappcorrisponde alla route/. - Rendering: Questo componente visualizza il contenuto della pagina principale.
- Integrazione del layout: Il componente
HomePageè avvolto dalayout.tsx, che può includere intestazioni, piè di pagina e altri elementi comuni.
Gestione di altri percorsi statici
Esempio: route /about
Struttura dei file:
arduinoCopy codemy-nextjs-app/
âââ app/
â âââ about/
â â âââ page.tsx
â âââ layout.tsx
â âââ page.tsx
âââ public/
âââ next.config.js
âââ ...
Implementazione:
// app/about/page.tsx
export default function AboutPage() {
return (
<div>
<h1>About Us</h1>
<p>Learn more about our mission and values.</p>
</div>
)
}
Spiegazione:
- Definizione della route: Il file
page.tsxallâinterno della cartellaaboutcorrisponde alla route/about. - Rendering: Questo componente esegue il rendering del contenuto della pagina about.
Route dinamiche
Le route dinamiche permettono di gestire percorsi con segmenti variabili, consentendo alle applicazioni di visualizzare contenuti basati su parametri come ID, slug, ecc.
Esempio: /posts/[id] Route
Struttura dei file:
arduinoCopy codemy-nextjs-app/
âââ app/
â âââ posts/
â â âââ [id]/
â â âââ page.tsx
â âââ layout.tsx
â âââ page.tsx
âââ public/
âââ next.config.js
âââ ...
Implementazione:
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>
);
}
Spiegazione:
- Segmento Dinamico:
[id]indica un segmento dinamico nella route, che cattura il parametroiddallâURL. - Accesso ai Parametri: Lâoggetto
paramscontiene i parametri dinamici, accessibili allâinterno del componente. - Matching delle Route: Qualsiasi percorso che corrisponde a
/posts/*, come/posts/1,/posts/abc, ecc., sarĂ gestito da questo componente.
Route annidate
Next.js supporta il routing annidato, consentendo strutture di route gerarchiche che rispecchiano la disposizione delle directory.
Esempio: /dashboard/settings/profile Route
Struttura dei File:
arduinoCopy codemy-nextjs-app/
âââ app/
â âââ dashboard/
â â âââ settings/
â â â âââ profile/
â â â âââ page.tsx
â â âââ page.tsx
â âââ layout.tsx
â âââ page.tsx
âââ public/
âââ next.config.js
âââ ...
Implementazione:
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>
);
}
Spiegazione:
- Nidificazione profonda: The
page.tsxfile insidedashboard/settings/profile/corresponds to the/dashboard/settings/profileroute. - Riflesso della gerarchia: La struttura delle directory riflette il percorso URL, migliorando manutenibilitĂ e chiarezza.
Rotte catch-all
Le rotte catch-all gestiscono piĂš segmenti nidificati o percorsi sconosciuti, fornendo flessibilitĂ nella gestione delle route.
Esempio: /* Route
Struttura del file:
my-nextjs-app/
âââ app/
â âââ [...slug]/
â â âââ page.tsx
â âââ layout.tsx
â âââ page.tsx
âââ public/
âââ next.config.js
âââ ...
Implementazione:
// 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>
)
}
Spiegazione:
- Catch-All Segment:
[...slug]cattura tutti i segmenti rimanenti del percorso come un array. - Usage: Utile per gestire scenari di routing dinamico come percorsi generati dagli utenti, categorie nidificate, ecc.
- Route Matching: Percorsi come
/anything/here,/foo/bar/baz, ecc., sono gestiti da questo componente.
Potenziali vulnerabilitĂ lato client
Sebbene Next.js fornisca una base sicura, pratiche di codifica improprie possono introdurre vulnerabilitĂ . Le principali vulnerabilitĂ lato client includono:
Cross-Site Scripting (XSS)
Gli attacchi XSS si verificano quando script malevoli vengono iniettati in siti web attendibili. Gli aggressori possono eseguire script nei browser degli utenti, rubare dati o eseguire azioni per conto dellâutente.
Esempio di codice vulnerabile:
// Dangerous: Injecting user input directly into HTML
function Comment({ userInput }) {
return <div dangerouslySetInnerHTML={{ __html: userInput }} />
}
PerchĂŠ è vulnerabile: Lâutilizzo di dangerouslySetInnerHTML con input non attendibili consente agli aggressori di iniettare script malevoli.
Client-Side Template Injection
Si verifica quando gli input degli utenti vengono gestiti in modo inappropriato nei template, permettendo agli attaccanti di iniettare ed eseguire template o espressioni.
Esempio di codice vulnerabile:
import React from "react"
import ejs from "ejs"
function RenderTemplate({ template, data }) {
const html = ejs.render(template, data)
return <div dangerouslySetInnerHTML={{ __html: html }} />
}
PerchĂŠ è vulnerabile: Se template o data contiene contenuto malevolo, può portare allâesecuzione di codice non previsto.
Client Path Traversal
Ă una vulnerabilitĂ che permette agli attaccanti di manipolare i percorsi client-side per eseguire azioni non previste, come Cross-Site Request Forgery (CSRF). A differenza del server-side path traversal, che prende di mira il filesystem del server, CSPT si concentra sullo sfruttamento dei meccanismi client-side per reindirizzare richieste API legittime verso endpoint malevoli.
Esempio di codice vulnerabile:
Unâapplicazione Next.js permette agli utenti di caricare e scaricare file. La funzionalitĂ di download è implementata lato client, dove gli utenti possono specificare il percorso del file da scaricare.
// 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>
)
}
Scenario di attacco
- Obiettivo dellâattaccante: Perform a CSRF attack to delete a critical file (e.g.,
admin/config.json) by manipulating thefilePath. - Sfruttamento di CSPT:
- Input maligno: Lâattaccante crea una URL con un
filePathmanipolato come../deleteFile/config.json. - Chiamata API risultante: Il codice client-side effettua una richiesta a
/api/files/../deleteFile/config.json. - Gestione dal server: Se il server non valida il
filePath, elabora la richiesta, potenzialmente cancellando o esponendo file sensibili.
- Esecuzione del CSRF:
- Link creato: Lâattaccante invia alla vittima un link o incorpora uno script maligno che forza la richiesta di download con il
filePathmanipolato. - Risultato: La vittima esegue inconsapevolmente lâazione, portando ad accesso o cancellazione non autorizzata di file.
PerchÊ è vulnerabile
- Mancanza di validazione degli input: Il client-side permette input arbitrari per
filePath, abilitando path traversal. - Fidarsi degli input dal client: LâAPI server-side si fida e processa il
filePathsenza sanitizzazione. - Possibili azioni dellâAPI: Se lâendpoint API esegue azioni che cambiano lo stato (es. delete, modify files), può essere sfruttato via CSPT.
Server-Side in Next.js
Server-Side Rendering (SSR)
Le pagine vengono renderizzate sul server ad ogni richiesta, assicurando che lâutente riceva HTML completamente renderizzato. In questo caso dovresti creare il tuo server personalizzato per processare le richieste.
Casi dâuso:
- Contenuto dinamico che cambia frequentemente.
- Ottimizzazione SEO, poichĂŠ i motori di ricerca possono eseguire il crawling della pagina completamente renderizzata.
Implementazione:
// 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
Generazione di siti statici (SSG)
Le pagine vengono pre-renderizzate in fase di build, risultando in tempi di caricamento piĂš rapidi e in un ridotto carico sul server.
Casi dâuso:
- Contenuti che non cambiano frequentemente.
- Blog, documentazione, pagine di marketing.
Implementazione:
// 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
Funzioni serverless (API Routes)
Next.js consente la creazione di endpoint API come funzioni serverless. Queste funzioni vengono eseguite on-demand senza la necessitĂ di un server dedicato.
Casi dâuso:
- Gestione degli invii di form.
- Interazione con database.
- Elaborazione dei dati o integrazione con API di terze parti.
Implementazione:
Con lâintroduzione della directory app in Next.js 13, il routing e la gestione delle API sono diventati piĂš flessibili e potenti. Questo approccio moderno si allinea strettamente con il sistema di routing basato sui file ma introduce capacitĂ aumentate, incluso il supporto per componenti server e client.
Basic Route Handler
File Structure:
my-nextjs-app/
âââ app/
â âââ api/
â âââ hello/
â âââ route.js
âââ package.json
âââ ...
Implementazione:
// 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))
Spiegazione:
- Posizione: API routes are placed under the
app/api/directory. - Nome file: Each API endpoint resides in its own folder containing a
route.jsorroute.tsfile. - Funzioni esportate: Instead of a single default export, specific HTTP method functions (e.g.,
GET,POST) are exported. - Gestione delle risposte: Use the
Responseconstructor to return responses, allowing more control over headers and status codes.
Come gestire altri percorsi e metodi:
Gestione di metodi HTTP specifici
Next.js 13+ allows you to define handlers for specific HTTP methods within the same route.js or route.ts file, promoting clearer and more organized code.
Esempio:
// 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" },
})
}
Spiegazione:
- Esportazioni multiple: Ogni metodo HTTP (
GET,PUT,DELETE) ha la propria funzione esportata. - Parametri: Il secondo argomento fornisce accesso ai parametri della route tramite
params. - Risposte migliorate: Maggiore controllo sugli oggetti di risposta, consentendo la gestione precisa di header e codici di stato.
Catch-All e route annidate
Next.js 13+ supporta funzionalitĂ di routing avanzate come route catch-all e route API annidate, consentendo strutture API piĂš dinamiche e scalabili.
Esempio di route 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" },
})
}
Spiegazione:
- Sintassi:
[...]indica un segmento catch-all, che cattura tutti i percorsi annidati. - Uso: Utile per API che devono gestire profonditĂ di route variabili o segmenti dinamici.
Esempio di route nidificate:
// 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" },
}
)
}
Spiegazione:
- Deep Nesting: Consente strutture API gerarchiche, che riflettono le relazioni tra le risorse.
- Parameter Access: Accedi facilmente a piĂš parametri di route tramite lâoggetto
params.
Gestione delle API routes in Next.js 12 e versioni precedenti
API Routes nella directory pages (Next.js 12 e versioni precedenti)
Prima che Next.js 13 introducesse la directory app e le capacità di routing migliorate, le API routes venivano principalmente definite nella directory pages. Questo approccio è ancora ampiamente usato e supportato in Next.js 12 e nelle versioni precedenti.
Route API di base
File Structure:
goCopy codemy-nextjs-app/
âââ pages/
â âââ api/
â âââ hello.js
âââ package.json
âââ ...
Implementazione:
javascriptCopy code// pages/api/hello.js
export default function handler(req, res) {
res.status(200).json({ message: 'Hello, World!' });
}
Spiegazione:
- Posizione: Le route API risiedono sotto la directory
pages/api/. - Export: Usa
export defaultper definire la funzione handler. - Firma della funzione: Lâhandler riceve gli oggetti
req(HTTP request) eres(HTTP response). - Routing: Il nome del file (
hello.js) mappa allâendpoint/api/hello.
Rotte API dinamiche
Struttura dei file:
bashCopy codemy-nextjs-app/
âââ pages/
â âââ api/
â âââ users/
â âââ [id].js
âââ package.json
âââ ...
Implementazione:
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`);
}
}
Spiegazione:
- Segmenti dinamici: Le parentesi quadre (
[id].js) indicano segmenti di route dinamici. - Accesso ai parametri: Usa
req.query.idper accedere al parametro dinamico. - Gestione dei metodi: Utilizza logica condizionale per gestire i diversi metodi HTTP (
GET,PUT,DELETE, ecc.).
Gestione dei diversi metodi HTTP
Mentre lâesempio base di API route gestisce tutti i metodi HTTP allâinterno di una singola funzione, puoi strutturare il tuo codice per gestire ciascun metodo esplicitamente per una maggiore chiarezza e manutenibilitĂ .
Esempio:
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`);
}
}
Migliori pratiche:
- Separazione delle responsabilitĂ : Separa chiaramente la logica per i diversi metodi HTTP.
- Coerenza delle risposte: Assicurati di mantenere strutture di risposta coerenti per facilitare la gestione lato client.
- Gestione degli errori: Gestisci in modo appropriato i metodi non supportati e gli errori imprevisti.
Configurazione CORS
Controlla quali origini possono accedere alle tue API routes, mitigando le vulnerabilitĂ legate a Cross-Origin Resource Sharing (CORS).
Esempio di configurazione errata:
// 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",
},
})
}
Nota che CORS può essere configurato anche in tutte le route API allâinterno del file 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
}
Problema:
Access-Control-Allow-Origin: '*': Permette a qualsiasi sito web di accedere allâAPI, potenzialmente consentendo a siti malevoli di interagire con la tua API senza restrizioni.- Ampia autorizzazione dei metodi: Consentire tutti i metodi può permettere agli attackers di eseguire azioni indesiderate.
Come attackers lo sfruttano:
Gli attackers possono creare siti web malevoli che inviano richieste alla tua API, potenzialmente abusando di funzionalitĂ come recupero dati, manipolazione dei dati o innescando azioni indesiderate per conto di utenti autenticati.
CORS - Misconfigurations & Bypass
Esposizione del codice server sul lato client
Ă facile riutilizzare codice usato dal server anche nel codice esposto e utilizzato dal lato client; il modo migliore per assicurarsi che un file di codice non venga mai esposto nel lato client è usare questo import allâinizio del file:
import "server-only"
File principali e i loro ruoli
middleware.ts / middleware.js
Posizione: Radice del progetto o nella cartella src/.
Scopo: Esegue codice nella funzione serverless lato server prima che venga elaborata una richiesta, permettendo attivitĂ come autenticazione, reindirizzamenti o modifica delle risposte.
Flusso di esecuzione:
- Richiesta in entrata: Il middleware intercetta la richiesta.
- Elaborazione: Esegue operazioni in base alla richiesta (es. verifica dellâautenticazione).
- Modifica della risposta: Può alterare la risposta o trasferire il controllo al handler successivo.
Esempi di utilizzo:
- Reindirizzare utenti non autenticati.
- Aggiungere header personalizzati.
- Registrare le richieste.
Esempio di configurazione:
// 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
Posizione: Radice del progetto.
Scopo: Configura il comportamento di Next.js, abilitando o disabilitando funzionalitĂ , personalizzando le configurazioni di webpack, impostando variabili dâambiente e configurando diverse funzionalitĂ di sicurezza.
Principali configurazioni di sicurezza:
Header di sicurezza
Gli header di sicurezza aumentano la protezione della tua applicazione indicando ai browser come gestire i contenuti. Aiutano a mitigare vari attacchi come Cross-Site Scripting (XSS), Clickjacking e lo sniffing dei tipi MIME:
- Content Security Policy (CSP)
- X-Frame-Options
- X-Content-Type-Options
- Strict-Transport-Security (HSTS)
- Referrer Policy
Esempi:
// 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...
],
},
]
},
}
Impostazioni di ottimizzazione delle immagini
Next.js ottimizza le immagini per le prestazioni, ma errori di configurazione possono portare a vulnerabilitĂ di sicurezza, ad esempio permettendo a origini non attendibili di iniettare contenuti malevoli.
Esempio di configurazione errata:
// next.config.js
module.exports = {
images: {
domains: ["*"], // Allows images from any domain
},
}
Problema:
'*': Permette il caricamento di immagini da qualsiasi fonte esterna, inclusi domini non attendibili o malevoli. Attackers possono ospitare immagini contenenti payloads malevoli o contenuti che fuorviano gli utenti.- Un altro problema potrebbe essere permettere un dominio dove chiunque può caricare unâimmagine (come
raw.githubusercontent.com)
How attackers abuse it:
Iniettando immagini da fonti malevole, Attackers possono eseguire phishing attacks, mostrare informazioni fuorvianti o sfruttare vulnerabilitĂ nelle librerie di rendering delle immagini.
Esposizione delle Variabili d'Ambiente
Gestire informazioni sensibili come API keys e credenziali del database in modo sicuro senza esporle al client.
a. Esposizione di Variabili Sensibili
Esempio di Configurazione Errata:
// 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
},
}
Problema:
SECRET_API_KEY: Senza il prefissoNEXT_PUBLIC_, Next.js non espone le variabili al client. Tuttavia, se viene prefissato per errore (es.NEXT_PUBLIC_SECRET_API_KEY), diventa accessibile dal lato client.
Come gli attaccanti lo sfruttano:
Se variabili sensibili sono esposte al client, gli attaccanti possono recuperarle ispezionando il codice lato client o le richieste di rete, ottenendo accesso non autorizzato ad API, database o altri servizi.
Reindirizzamenti
Gestisci i reindirizzamenti e le riscritture URL allâinterno della tua applicazione, assicurandoti che gli utenti vengano indirizzati correttamente senza introdurre vulnerabilitĂ di open redirect.
a. Open Redirect Vulnerability
Esempio di cattiva configurazione:
// next.config.js
module.exports = {
async redirects() {
return [
{
source: "/redirect",
destination: (req) => req.query.url, // Dynamically redirects based on query parameter
permanent: false,
},
]
},
}
Problema:
- Destinazione dinamica: Permette agli utenti di specificare qualsiasi URL, consentendo attacchi di open redirect.
- Affidarsi ai dati forniti dallâutente: I redirect verso URL forniti dagli utenti senza validazione possono portare a phishing, malware distribution o credential theft.
Come gli attaccanti lo sfruttano:
Gli attaccanti possono creare URL che sembrano provenire dal tuo dominio ma reindirizzano gli utenti su siti malevoli. Per esempio:
https://yourdomain.com/redirect?url=https://malicious-site.com
Gli utenti che si fidano del dominio originale potrebbero navigare inconsapevolmente su siti dannosi.
Configurazione Webpack
Personalizza le configurazioni di Webpack per la tua applicazione Next.js, che possono introdurre involontariamente vulnerabilitĂ di sicurezza se non gestite con cautela.
a. Esposizione di Moduli Sensibili
Esempio di Configurazione Errata:
// next.config.js
module.exports = {
webpack: (config, { isServer }) => {
if (!isServer) {
config.resolve.alias["@sensitive"] = path.join(__dirname, "secret-folder")
}
return config
},
}
Problema:
- Esposizione di Percorsi Sensibili: Lâaliasing di directory sensibili e il consentire lâaccesso client-side possono leak informazioni confidenziali.
- Bundling Secrets: Se file sensibili vengono inclusi nel bundle per il client, i loro contenuti diventano accessibili tramite source maps o ispezionando il client-side code.
Come gli attaccanti lo sfruttano:
Gli attaccanti possono accedere o ricostruire la struttura delle directory dellâapplicazione, trovando potenzialmente e sfruttando file o dati sensibili.
pages/_app.js e pages/_document.js
pages/_app.js
Scopo: Sovrascrive il componente App predefinito, permettendo stato globale, stili e componenti di layout.
Casi dâuso:
- Iniettare CSS globale.
- Aggiungere wrapper di layout.
- Integrare librerie per la gestione dello stato.
Esempio:
// pages/_app.js
import "../styles/globals.css"
function MyApp({ Component, pageProps }) {
return <Component {...pageProps} />
}
export default MyApp
pages/_document.js
Scopo: Sovrascrive il Document predefinito, permettendo la personalizzazione dei tag HTML e Body.
Casi dâuso:
- Modificare i tag
<html>o<body>. - Aggiungere meta tag o script personalizzati.
- Integrare font di terze parti.
Esempio:
// 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
Server personalizzato (Opzionale)
Scopo: Sebbene Next.js venga fornito con un server integrato, puoi creare un server personalizzato per casi dâuso avanzati come routing personalizzato o integrazione con servizi backend esistenti.
Nota: Lâutilizzo di un server personalizzato può limitare le opzioni di deployment, specialmente su piattaforme come Vercel che ottimizzano per il server integrato di Next.js.
Esempio:
// 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")
})
})
Considerazioni aggiuntive sullâarchitettura e la sicurezza
Variabili dâambiente e configurazione
Scopo: Gestire informazioni sensibili e impostazioni di configurazione al di fuori del codice.
Buone pratiche:
- Usa file
.env: Salva variabili come API keys in.env.local(escluso dal controllo di versione). - Accedi alle variabili in modo sicuro: Usa
process.env.VARIABLE_NAMEper accedere alle variabili dâambiente. - Non esporre mai secrets sul client: Assicurati che le variabili sensibili siano usate solo server-side.
Esempio:
// 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
},
}
Nota: Per limitare le variabili solo al lato server, omettile dallâoggetto env o prefissale con NEXT_PUBLIC_ per lâesposizione al client.
Autenticazione e Autorizzazione
Approccio:
- Session-Based Authentication: Usa cookie per gestire le sessioni utente.
- Token-Based Authentication: Implementa JWTs per autenticazione senza stato.
- Third-Party Providers: Integra con provider OAuth (es. Google, GitHub) usando librerie come
next-auth.
Pratiche di sicurezza:
- Secure Cookies: Imposta gli attributi
HttpOnly,SecureeSameSite. - Password Hashing: Esegui sempre lâhash delle password prima di memorizzarle.
- Input Validation: Previeni attacchi di injection validando e sanificando gli input.
Esempio:
// 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" })
}
}
Ottimizzazione delle prestazioni
Strategie:
- Ottimizzazione delle immagini: Usa il componente
next/imagedi Next.js per lâottimizzazione automatica delle immagini. - Suddivisione del codice: Sfrutta gli import dinamici per suddividere il codice e ridurre i tempi di caricamento iniziali.
- Caching: Implementa strategie di caching per le risposte API e le risorse statiche.
- Lazy Loading: Carica componenti o risorse solo quando sono necessari.
Esempio:
// Dynamic Import with Code Splitting
import dynamic from "next/dynamic"
const HeavyComponent = dynamic(() => import("../components/HeavyComponent"), {
loading: () => <p>Loading...</p>,
})
Next.js Server Actions Enumerazione (hash to function name via source maps)
Next.js moderno usa âServer Actionsâ che vengono eseguite sul server ma sono invocate dal client. In produzione queste invocazioni sono opache: tutte le POSTs arrivano su un endpoint comune e sono distinte da un hash specifico della build inviato nellâheader Next-Action. Esempio:
POST /
Next-Action: a9f8e2b4c7d1...
Quando productionBrowserSourceMaps è abilitato, i chunk JS minificati contengono chiamate a createServerReference(...) che leak enough structure (piĂš gli source maps associati) per recuperare una mappatura tra lâhash dellâazione e il nome originale della funzione. Questo permette di tradurre gli hash osservati in Next-Action in target concreti come deleteUserAccount() o exportFinancialData().
Approccio di estrazione (regex on minified JS + optional source maps)
Cerca nei chunk JS scaricati createServerReference ed estrai lâhash e il simbolo funzione/sorgente. Due pattern utili:
# 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*\)
- Gruppo 1: server action hash (40+ caratteri esadecimali)
- Gruppo 2: simbolo o percorso che può essere risolto al nome della funzione originale tramite la source map, se presente
Se lo script pubblicizza una source map (commento trailer //# sourceMappingURL=<...>.map), recuperala e risolvi il simbolo/percorso nel nome della funzione originale.
Flusso di lavoro pratico
- Scoperta passiva durante la navigazione: cattura le richieste con header
Next-Actione gli URL dei JS chunk. - Recupera i bundle JS referenziati e i file
*.mapassociati (quando presenti). - Esegui la regex sopra per costruire un dizionario hashâname.
- Usa il dizionario per indirizzare i test:
- Name-driven triage (es.
transferFunds,exportFinancialData). - Monitora la copertura tra le build per nome funzione (gli hash ruotano tra le build).
Esecuzione di hidden actions (richiesta basata su template)
Prendi un POST valido osservato in-proxy come template e sostituisci il valore Next-Action per mirare a unâaltra action scoperta:
# Before
Next-Action: a9f8e2b4c7d1
# After
Next-Action: b7e3f9a2d8c5
Riproduci in Repeater e testa authorization, input validation e business logic di azioni altrimenti irraggiungibili.
Automazione di Burp
- NextjsServerActionAnalyzer (estensione per Burp) automatizza quanto sopra in Burp:
- Scava nella cronologia del proxy per JS chunks, estrae le voci
createServerReference(...), e analizza le source maps quando disponibili. - Mantiene un dizionario hashâfunction-name ricercabile e rimuove duplicati tra build basandosi sul nome della funzione.
- Può individuare un POST template valido e aprire una tab di Repeater pronta da inviare con lâhash dellâazione target sostituito.
- Repo: https://github.com/Adversis/NextjsServerActionAnalyzer
Note e limitazioni
- Richiede
productionBrowserSourceMapsabilitato in produzione per recuperare i nomi dai bundles/source maps. - La divulgazione del nome della funzione non è di per sĂŠ una vulnerabilitĂ ; usala per guidare la scoperta e testare lâautorizzazione di ciascuna action.
RCE di deserializzazione del protocollo Flight di React Server Components (CVE-2025-55182)
Le deployment Next.js App Router che espongono Server Actions su react-server-dom-webpack 19.0.0â19.2.0 (Next.js 15.x/16.x) contengono una critica server-side prototype pollution durante la deserializzazione dei chunk Flight. Manipolando riferimenti $ allâinterno di un payload Flight un attacker può pivotare da prototype polluted a esecuzione arbitraria di JavaScript e quindi a esecuzione di comandi OS nel processo Node.js.
NodeJS - proto & prototype Pollution
Catena dâattacco nei chunk Flight
- Primitive di prototype pollution: Imposta
"then": "$1:__proto__:then"in modo che il resolver scriva una funzionethensuObject.prototype. Qualsiasi plain object processato successivamente diventa thenable, permettendo allâattacker di influenzare il controllo di flusso async allâinterno degli internals RSC. - Ricollegamento al costruttore globale
Function: Punta_response._formData.getverso"$1:constructor:constructor". Durante la risoluzione,object.constructorâObject, eObject.constructorâFunction, quindi chiamate successive a_formData.get()eseguono effettivamenteFunction(...). - Esecuzione di codice tramite
_prefix: Inserisci sorgente JavaScript in_response._prefix. Quando il_formData.getinquinato viene invocato, il framework valutaFunction(_prefix)(...), quindi il JS iniettato può eseguirerequire('child_process').exec()o qualsiasi altro primitivo Node.
Scheletro del payload
{
"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" }
}
}
Mappatura dellâesposizione delle React Server Functions
Le React Server Functions (RSF) sono qualsiasi funzione che includa la direttiva 'use server';. Ogni form action, mutation, o fetch helper legato a una di queste funzioni diventa un RSC Flight endpoint che deserializzerĂ senza problemi payload forniti dallâattaccante. Passi di recon utili derivati dalle valutazioni di React2Shell:
- Inventario statico: cerca la direttiva per capire quante RSF vengono esposte automaticamente dal framework.
rg -n "'use server';" -g"*.{js,ts,jsx,tsx}" app/
- App Router defaults:
create-next-appabilita lâApp Router + la directoryapp/di default, che silenziosamente trasforma ogni route in un endpoint RSC-capable. App Router assets such as/_next/static/chunks/app/or responses that stream Flight chunks overtext/x-componentsono strong Internet-facing fingerprints. - Implicitly vulnerable RSC deployments: Lâavviso ufficiale di React segnala che le app che distribuiscono il runtime RSC possono essere sfruttabili anche senza RSFs espliciti, quindi considera sospetto qualsiasi build che utilizza
react-server-dom-*19.0.0â19.2.0. - Other frameworks bundling RSC: Vite RSC, Parcel RSC, React Router RSC preview, RedwoodSDK, Waku, etc. riutilizzano lo stesso serializzatore e ereditano la medesima superficie di attacco remota finchĂŠ non incorporano build React patchate.
Version coverage (React2Shell)
react-server-dom-webpack,react-server-dom-parcel,react-server-dom-turbopack: vulnerabili in 19.0.0, 19.1.0â19.1.1 e 19.2.0; patchate in 19.0.1, 19.1.2 e 19.2.1 rispettivamente.- Next.js stable: App Router releases 15.0.0â16.0.6 incorporano lo stack RSC vulnerabile. I patch trains 15.0.5 / 15.1.9 / 15.2.6 / 15.3.6 / 15.4.8 / 15.5.7 / 16.0.7 includono dipendenze corrette, quindi qualsiasi build al di sotto di quelle versioni è di alto valore.
- Next.js canary:
14.3.0-canary.77+include anchâesso il runtime buggy e attualmente manca di canary drops patchate, rendendo quei fingerprints candidati forti per lo sfruttamento.
Remote detection oracle
Lo strumento di Assetnoteâs react2shell-scanner invia una Flight request multipart creata ad hoc ai percorsi candidati e osserva il comportamento lato server:
- Default mode esegue un payload RCE deterministico (operazione matematica riflessa via
X-Action-Redirect) che prova lâesecuzione di codice. --safe-checkmode malforma volontariamente il messaggio Flight in modo che i server patchati rispondano200/400, mentre i target vulnerabili emettono risposteHTTP/500contenenti la sottostringaE{"digest"nel body. Questa coppia(500 + digest)è attualmente lâoracolo remoto piĂš affidabile pubblicato dai difensori.- Gli switch integrati
--waf-bypass,--vercel-waf-bypass, e--windowsaggiustano il layout del payload, premettono junk, o sostituiscono comandi OS in modo da poter sondare asset reali su Internet.
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
Riferimenti
- Pentesting Next.js Server Actions â Unâestensione di Burp per la mappatura da hash a funzione
- NextjsServerActionAnalyzer (Burp extension)
- CVE-2025-55182 React Server Components Remote Code Execution Exploit Tool
- CVE-2025-55182 & CVE-2025-66478 React2Shell â Tutto quello che devi sapere
- assetnote/react2shell-scanner
Tip
Impara e pratica il hacking AWS:
HackTricks Training AWS Red Team Expert (ARTE)
Impara e pratica il hacking GCP:HackTricks Training GCP Red Team Expert (GRTE)
Impara e pratica il hacking Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Supporta HackTricks
- Controlla i piani di abbonamento!
- Unisciti al đŹ gruppo Discord o al gruppo telegram o seguici su Twitter đŚ @hacktricks_live.
- Condividi trucchi di hacking inviando PR ai HackTricks e HackTricks Cloud repos github.
HackTricks

