Bevezetés: Miért kritikus a middleware biztonság a Next.js alkalmazásokban?
Ha Next.js-sel dolgozol, valószínűleg tudod, hogy az App Router middleware rétege az egyik legfontosabb védelmi vonal az alkalmazásodban. Ez a köztes szoftver fut le elsőként minden bejövő kérésnél — még mielőtt az oldal renderelése vagy bármilyen adatbázis-lekérdezés elkezdődne. Éppen ezért a middleware helyes beállítása és biztonsági megerősítése nem opcionális, hanem alapvető fontosságú.
2025 márciusában viszont egy elég kellemetlen meglepetés érte a közösséget.
A CVE-2025-29927 azonosítójú sebezhetőség felfedezése rávilágított, hogy a middleware-re épülő hitelesítési rendszerek önmagukban nem nyújtanak elegendő védelmet. Ez a kritikus sérülékenység lehetővé tette, hogy a támadók egy speciálisan összeállított HTTP fejléccel egyszerűen megkerüljék a middleware összes védelmi mechanizmusát. Igen, az összeset.
Ebben az útmutatóban részletesen áttekintjük a Next.js middleware biztonsági architektúráját, bemutatjuk a mélységi védelmi (defense-in-depth) stratégiákat, és gyakorlati kódpéldákon keresztül megismerkedünk a legbiztonságosabb hitelesítési mintákkal 2026-ban. Szóval, vágjunk bele!
A CVE-2025-29927 sebezhetőség: Mit tanulhatunk belőle?
A sérülékenység technikai háttere
A CVE-2025-29927 egy tervezési hibából fakadt, ami a Next.js x-middleware-subrequest belső fejlécének kezelését érintette. Ezt a fejlécet eredetileg arra tervezték, hogy megakadályozza a middleware végtelen ciklusba kerülését az alkérések során. A gond az volt, hogy a keretrendszer nem ellenőrizte megfelelően, vajon ez a fejléc tényleg belső forrásból érkezik-e.
// Így lehetett megkerülni a middleware-t (SEBEZHETŐ verzió)
// Egyetlen HTTP kérés a speciális fejléccel:
fetch('https://pelda.hu/vedett-oldal', {
headers: {
'x-middleware-subrequest': 'middleware'
}
});
Ennyi volt az egész. A támadó ezzel a módszerrel teljesen kikerülhette a middleware által végrehajtott hitelesítési ellenőrzéseket, CSP szabályokat és gyorsítótár-kezelési logikát. Őszintén szólva, ez elég ijesztő.
Érintett verziók
A sebezhetőség a következő Next.js verziókat érintette:
- Next.js 15.x — 15.2.3 előtti verziók
- Next.js 14.x — 14.2.25 előtti verziók
- Next.js 13.x — 13.5.9 előtti verziók
- Next.js 12.x — 12.3.5 előtti verziók
A legfontosabb tanulság
A CVE-2025-29927 legfontosabb tanulsága egyértelmű: soha ne bízzunk kizárólag a middleware rétegre a hitelesítés és jogosultságkezelés terén. A middleware legyen az első védelmi vonal, de semmiképp sem az egyetlen. Ez a mélységi védelem (defense-in-depth) elve, amit a következő fejezetekben alaposan körbejárunk.
A Next.js middleware működése az App Routerben
Az Edge Runtime és a middleware futási környezete
A Next.js middleware az Edge Runtime környezetben fut, ami annyit jelent, hogy a szerver és a kliens között, a hálózat szélén hajtódik végre. Ez gyors válaszidőt eredményez, de korlátokat is jelent: nem érhető el a teljes Node.js API, nem használhatók natív modulok, és a futási idő is limitált.
// middleware.ts — Alapvető middleware struktúra
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';
export function middleware(request: NextRequest) {
// Az Edge Runtime-ban futunk
// Hozzáférünk a kérés fejléceihez, cookie-jaihoz, URL-jéhez
const token = request.cookies.get('session-token')?.value;
if (!token && request.nextUrl.pathname.startsWith('/dashboard')) {
return NextResponse.redirect(new URL('/bejelentkezes', request.url));
}
return NextResponse.next();
}
// Milyen útvonalakra fusson a middleware
export const config = {
matcher: ['/dashboard/:path*', '/api/:path*', '/profil/:path*'],
};
A matcher konfigurálás fontossága
A matcher konfiguráció határozza meg, hogy a middleware mely útvonalakon fusson le. Fontos, hogy pontosan definiáljuk ezeket, különben a middleware vagy túl sok, vagy túl kevés kérést fog feldolgozni (és mindkét eset problémás).
// Helyes matcher konfiguráció
export const config = {
matcher: [
// Védett oldalak
'/dashboard/:path*',
'/admin/:path*',
'/profil/:path*',
// API végpontok (kivéve a publikusakat)
'/api/((?!public|webhook).*)',
// Statikus fájlok kihagyása
'/((?!_next/static|_next/image|favicon.ico|public).*)',
],
};
Mélységi védelmi stratégia (Defense-in-Depth)
Mi az a mélységi védelem?
A mélységi védelem egy biztonsági stratégia, amely több egymásra épülő védelmi réteget alkalmaz. Ha az egyik réteg meghiúsul — mint ahogy a CVE-2025-29927 esetében a middleware réteg kijátszható volt —, a többi réteg továbbra is védelmet nyújt. A Next.js App Router architektúrájában ez a következő rétegeket jelenti:
- Edge/Proxy réteg — Reverse proxy vagy CDN szintű védelmi szabályok
- Middleware réteg — Első szintű hitelesítés és átirányítás
- Server Component réteg — Adatlekérdezéseknél történő jogosultságellenőrzés
- Data Access Layer — Az adatbázis-hozzáférés szintjén végzett hitelesítés
- Server Action réteg — Minden mutáció előtti jogosultságellenőrzés
Nézzük meg egyenként ezeket a rétegeket.
1. réteg: Edge/Proxy szintű védelem
Az első védelmi vonalat a reverse proxy vagy az edge hálózat biztosítja. Itt tudjuk kiszűrni a gyanús fejléceket, beleértve a hírhedt x-middleware-subrequest fejlécet is.
# Nginx konfiguráció — gyanús fejlécek szűrése
server {
location / {
# A belső Next.js fejléc blokkolása külső forrásból
proxy_set_header x-middleware-subrequest "";
# Egyéb biztonsági fejlécek beállítása
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_pass http://localhost:3000;
}
}
Ha Vercelen hosztolod az alkalmazásod, ez a védelem automatikusan biztosított, mert a Vercel edge hálózata szűri ezeket a fejléceket. Saját infrastruktúrán viszont ezt neked kell beállítanod — ne felejtsd el!
2. réteg: Middleware szintű hitelesítés
A middleware továbbra is az első alkalmazásszintű védelmi vonal, de most már tisztában vagyunk a korlátaival. Használjuk gyors ellenőrzésekre és átirányításokra, de ne bízzuk rá a teljes jogosultságkezelést.
// middleware.ts — Robusztus middleware implementáció
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';
import { jwtVerify } from 'jose';
const VEDETT_UTVONALAK = ['/dashboard', '/admin', '/profil', '/beallitasok'];
const PUBLIKUS_UTVONALAK = ['/bejelentkezes', '/regisztracio', '/api/public'];
export async function middleware(request: NextRequest) {
const { pathname } = request.nextUrl;
// Publikus útvonalak átengedése
if (PUBLIKUS_UTVONALAK.some(ut => pathname.startsWith(ut))) {
return NextResponse.next();
}
// Védett útvonalak ellenőrzése
const isVedett = VEDETT_UTVONALAK.some(ut => pathname.startsWith(ut));
if (!isVedett) {
return NextResponse.next();
}
// Token ellenőrzés
const token = request.cookies.get('auth-token')?.value;
if (!token) {
const bejelentkezesUrl = new URL('/bejelentkezes', request.url);
bejelentkezesUrl.searchParams.set('visszaút', pathname);
return NextResponse.redirect(bejelentkezesUrl);
}
try {
// JWT token gyors ellenőrzése az Edge Runtime-ban
const titkosKulcs = new TextEncoder().encode(
process.env.JWT_SECRET
);
const { payload } = await jwtVerify(token, titkosKulcs);
// Admin útvonalak extra ellenőrzése
if (pathname.startsWith('/admin') && payload.role !== 'admin') {
return NextResponse.redirect(new URL('/nincs-jogosultsag', request.url));
}
// Felhasználói információ hozzáadása a fejléchez
const valasz = NextResponse.next();
valasz.headers.set('x-user-id', payload.sub as string);
valasz.headers.set('x-user-role', payload.role as string);
return valasz;
} catch (hiba) {
// Érvénytelen token — átirányítás bejelentkezéshez
const bejelentkezesUrl = new URL('/bejelentkezes', request.url);
return NextResponse.redirect(bejelentkezesUrl);
}
}
export const config = {
matcher: ['/((?!_next/static|_next/image|favicon.ico).*)'],
};
3. réteg: Data Access Layer — Az adathozzáférés védelme
A Data Access Layer (DAL) minta 2025–2026-ban a Next.js ökoszisztéma egyik legfontosabb biztonsági mintájává vált. A lényege egyszerű: minden adatbázis-művelet előtt ellenőrizzük a felhasználó jogosultságait, függetlenül attól, hogy a middleware már megtette-e ezt. Szóval dupla biztosítás, ha úgy tetszik.
// lib/dal.ts — Data Access Layer implementáció
import { cookies } from 'next/headers';
import { cache } from 'react';
import { redirect } from 'next/navigation';
import { jwtVerify } from 'jose';
// Hitelesített munkamenet lekérése (gyorsítótárazva a kérés életciklusára)
export const getHitelesitettMunkamenet = cache(async () => {
const cookieTarolo = await cookies();
const token = cookieTarolo.get('auth-token')?.value;
if (!token) {
redirect('/bejelentkezes');
}
try {
const titkosKulcs = new TextEncoder().encode(
process.env.JWT_SECRET
);
const { payload } = await jwtVerify(token, titkosKulcs);
return {
felhasznaloId: payload.sub as string,
szerepkor: payload.role as string,
email: payload.email as string,
};
} catch {
redirect('/bejelentkezes');
}
});
// Védett adatlekérdezés — felhasználó profil
export async function getFelhasznaloProfil(felhasznaloId: string) {
// MINDIG ellenőrizzük a jogosultságot az adathozzáférésnél
const munkamenet = await getHitelesitettMunkamenet();
// Felhasználó csak a saját profilját kérdezheti le (vagy admin)
if (munkamenet.felhasznaloId !== felhasznaloId &&
munkamenet.szerepkor !== 'admin') {
throw new Error('Nincs jogosultság a profil megtekintéséhez');
}
// Biztonságos adatlekérdezés
const profil = await db.felhasznalok.findUnique({
where: { id: felhasznaloId },
select: {
id: true,
nev: true,
email: true,
profilkep: true,
// Jelszó és egyéb érzékeny adatok SOHA nem kerülnek lekérdezésre
},
});
return profil;
}
// Admin-szintű adatlekérdezés
export async function getOsszesFelhasznalo() {
const munkamenet = await getHitelesitettMunkamenet();
if (munkamenet.szerepkor !== 'admin') {
throw new Error('Csak adminisztrátorok férhetnek hozzá');
}
return db.felhasznalok.findMany({
select: { id: true, nev: true, email: true, szerepkor: true },
orderBy: { letrehozva: 'desc' },
});
}
4. réteg: Server Component szintű védelem
A Server Componentek közvetlenül használják a Data Access Layert, így az adathozzáférés mindig védett — még akkor is, ha a middleware réteg kompromittálódna. Ez az, amiért a mélységi védelem annyira hatékony.
// app/dashboard/page.tsx — Védett Server Component
import { getHitelesitettMunkamenet } from '@/lib/dal';
import { getFelhasznaloProfil } from '@/lib/dal';
import { Suspense } from 'react';
export default async function IranyitopultOldal() {
// A DAL automatikusan ellenőrzi a jogosultságot
const munkamenet = await getHitelesitettMunkamenet();
return (
<div className="dashboard-container">
<h1>Üdvözöljük, {munkamenet.email}!</h1>
<Suspense fallback={<ProfilVazSkeleton />}>
<ProfilOsszefoglalo felhasznaloId={munkamenet.felhasznaloId} />
</Suspense>
<Suspense fallback={<TevekenysegiVazSkeleton />}>
<LegutobbiTevekenysegek felhasznaloId={munkamenet.felhasznaloId} />
</Suspense>
</div>
);
}
async function ProfilOsszefoglalo({
felhasznaloId
}: {
felhasznaloId: string
}) {
// Minden adatlekérdezés a DAL-on keresztül történik
const profil = await getFelhasznaloProfil(felhasznaloId);
return (
<div className="profil-kartya">
<img src={profil?.profilkep} alt="Profilkép" />
<h2>{profil?.nev}</h2>
<p>{profil?.email}</p>
</div>
);
}
5. réteg: Server Action védelem
A Server Actionök különösen fontos védelmi pontot képeznek, mivel ezeken keresztül módosítják a felhasználók az adatokat. Minden Server Actionben kötelezően ellenőrizni kell a jogosultságot, és validálni kell a bemeneti adatokat. Nincs kivétel, nincs "majd a middleware úgyis elkapja" mentalitás.
// app/actions/profil-muveletek.ts
'use server';
import { getHitelesitettMunkamenet } from '@/lib/dal';
import { z } from 'zod';
import { revalidatePath } from 'next/cache';
// Bemeneti validációs séma Zod-dal
const profilFrissitesSchema = z.object({
nev: z.string()
.min(2, 'A név legalább 2 karakter legyen')
.max(100, 'A név legfeljebb 100 karakter lehet'),
bio: z.string()
.max(500, 'Az életrajz legfeljebb 500 karakter lehet')
.optional(),
});
export async function profilFrissites(formData: FormData) {
// 1. MINDIG hitelesítés ellenőrzése
const munkamenet = await getHitelesitettMunkamenet();
// 2. Bemeneti adatok validálása
const nyers = {
nev: formData.get('nev'),
bio: formData.get('bio'),
};
const validalas = profilFrissitesSchema.safeParse(nyers);
if (!validalas.success) {
return {
siker: false,
hibak: validalas.error.flatten().fieldErrors,
};
}
// 3. Adatbázis-művelet végrehajtása
try {
await db.felhasznalok.update({
where: { id: munkamenet.felhasznaloId },
data: {
nev: validalas.data.nev,
bio: validalas.data.bio,
frissitve: new Date(),
},
});
// 4. Gyorsítótár érvénytelenítése
revalidatePath('/profil');
revalidatePath('/dashboard');
return { siker: true };
} catch (hiba) {
console.error('Profil frissítési hiba:', hiba);
return {
siker: false,
hibak: { altalanos: ['Váratlan hiba történt. Próbálja újra később.'] },
};
}
}
// Admin művelet — felhasználó törlése
export async function felhasznaloTorles(felhasznaloId: string) {
// Dupla ellenőrzés: hitelesítés ÉS jogosultság
const munkamenet = await getHitelesitettMunkamenet();
if (munkamenet.szerepkor !== 'admin') {
throw new Error('Csak adminisztrátorok törölhetnek felhasználókat');
}
// Önmaga törlésének megakadályozása
if (munkamenet.felhasznaloId === felhasznaloId) {
return {
siker: false,
hiba: 'Nem törölheti saját fiókját',
};
}
await db.felhasznalok.delete({
where: { id: felhasznaloId },
});
revalidatePath('/admin/felhasznalok');
return { siker: true };
}
Hitelesítési szolgáltatók integrálása 2026-ban
A modern hitelesítési ökoszisztéma
2026-ban már számos érett hitelesítési szolgáltató támogatja teljes körűen a Next.js App Router architektúráját. A kulcskérdés az, hogy a választott megoldás zökkenőmentesen működjön a Server Componentekkel, a Server Actionökkel és a middleware-rel egyaránt. Nézzük a két legnépszerűbb opciót.
NextAuth.js (Auth.js) v5 integráció
A NextAuth.js (mostantól Auth.js) v5 verziója natívan támogatja az App Routert, és beépített mélységi védelmi mintákat kínál. Személyes tapasztalatom szerint ez a legtöbb projekthez tökéletesen megfelel.
// auth.ts — Auth.js v5 konfiguráció
import NextAuth from 'next-auth';
import GitHub from 'next-auth/providers/github';
import Google from 'next-auth/providers/google';
import Credentials from 'next-auth/providers/credentials';
import { PrismaAdapter } from '@auth/prisma-adapter';
import { prisma } from '@/lib/prisma';
export const { handlers, auth, signIn, signOut } = NextAuth({
adapter: PrismaAdapter(prisma),
providers: [
GitHub({
clientId: process.env.GITHUB_ID,
clientSecret: process.env.GITHUB_SECRET,
}),
Google({
clientId: process.env.GOOGLE_ID,
clientSecret: process.env.GOOGLE_SECRET,
}),
Credentials({
credentials: {
email: { label: 'Email', type: 'email' },
jelszo: { label: 'Jelszó', type: 'password' },
},
authorize: async (credentials) => {
// Saját hitelesítési logika
const felhasznalo = await prisma.user.findUnique({
where: { email: credentials.email as string },
});
if (!felhasznalo) return null;
const jelszóEgyezik = await bcrypt.compare(
credentials.jelszo as string,
felhasznalo.hashedPassword
);
return jelszóEgyezik ? felhasznalo : null;
},
}),
],
callbacks: {
authorized: async ({ auth: munkamenet }) => {
return !!munkamenet;
},
},
pages: {
signIn: '/bejelentkezes',
error: '/hitelesitesi-hiba',
},
});
// middleware.ts — Auth.js middleware integráció
export { auth as middleware } from '@/auth';
export const config = {
matcher: ['/((?!api/auth|_next/static|_next/image|favicon.ico).*)'],
};
Clerk integráció az App Routerrel
A Clerk egy másik kiváló megoldás, ami 2026-ban az egyik legegyszerűbb integrációt kínálja. Ha gyorsan akarsz haladni és nem akarod a hitelesítést a nulláról felépíteni, érdemes megnézni.
// middleware.ts — Clerk middleware
import { clerkMiddleware, createRouteMatcher } from '@clerk/nextjs/server';
const isVedettUtvonal = createRouteMatcher([
'/dashboard(.*)',
'/profil(.*)',
'/admin(.*)',
]);
export default clerkMiddleware(async (auth, req) => {
if (isVedettUtvonal(req)) {
await auth.protect();
}
});
export const config = {
matcher: ['/((?!.*\\..*|_next).*)', '/', '/(api|trpc)(.*)'],
};
// app/dashboard/page.tsx — Clerk Server Component használat
import { auth, currentUser } from '@clerk/nextjs/server';
export default async function IranyitopultOldal() {
// Server Component szintű hitelesítés — nem függ a middleware-től!
const { userId } = await auth();
if (!userId) {
redirect('/bejelentkezes');
}
const felhasznalo = await currentUser();
return (
<div>
<h1>Üdvözöljük, {felhasznalo?.firstName}!</h1>
</div>
);
}
Server Action biztonsági minták
A Server Actionök különleges biztonsági kihívásai
Ez egy olyan pont, aminél érdemes egy kicsit elidőzni. A Server Actionök esetében van egy kritikus biztonsági szempont, amit sokan figyelmen kívül hagynak: amikor meghívunk egy Server Actiont, a Next.js egy HTTP kérést indít az aktuális útvonalhoz egy speciális fejléccel. Ez azt jelenti, hogy ha a Server Actiont egy másik útvonalról hívjuk meg, a middleware szabályai nem feltétlenül érvényesülnek.
// HELYTELEN: A Server Action nem ellenőrzi a jogosultságot
'use server';
export async function veszelyesMuvelet(adatok: FormData) {
// ❌ Nincs hitelesítés-ellenőrzés!
// A middleware elvileg védi az útvonalat, de...
// ...egy másik útvonalról is meghívható ez a Server Action!
await db.fontosTablat.delete({ where: { id: adatok.get('id') } });
}
// HELYES: Minden Server Action önállóan ellenőrzi a jogosultságot
'use server';
import { getHitelesitettMunkamenet } from '@/lib/dal';
import { z } from 'zod';
const torlesSchema = z.object({
id: z.string().uuid('Érvénytelen azonosító'),
});
export async function biztonsagosMuvelet(adatok: FormData) {
// ✅ Önálló hitelesítés-ellenőrzés
const munkamenet = await getHitelesitettMunkamenet();
// ✅ Jogosultság ellenőrzése
if (munkamenet.szerepkor !== 'admin') {
throw new Error('Nincs jogosultság');
}
// ✅ Bemenet validálása
const validalt = torlesSchema.parse({
id: adatok.get('id'),
});
// ✅ Csak validált adatokkal dolgozunk
await db.fontosTablat.delete({ where: { id: validalt.id } });
revalidatePath('/admin');
}
Rate limiting Server Actionökhöz
A Server Actionöket érdemes sebességkorlátozással is védeni a brute force támadások ellen. Egy egyszerű in-memory megoldás sok esetben elég jó kiindulópont:
// lib/rate-limit.ts — Egyszerű in-memory rate limiter
const keresSzamlalo = new Map<string, { szam: number; lejarat: number }>();
export function rateLimit(
azonosito: string,
maxKeres: number = 10,
idoablakMp: number = 60
): boolean {
const most = Date.now();
const kulcs = azonosito;
const meglevo = keresSzamlalo.get(kulcs);
if (!meglevo || meglevo.lejarat < most) {
keresSzamlalo.set(kulcs, {
szam: 1,
lejarat: most + idoablakMp * 1000,
});
return true; // Engedélyezve
}
if (meglevo.szam >= maxKeres) {
return false; // Túllépve a korlát
}
meglevo.szam++;
return true; // Engedélyezve
}
// Használat Server Actionben
'use server';
import { headers } from 'next/headers';
import { rateLimit } from '@/lib/rate-limit';
export async function bejelentkezesAction(formData: FormData) {
const fejlecek = await headers();
const ip = fejlecek.get('x-forwarded-for') ?? 'ismeretlen';
if (!rateLimit(ip, 5, 300)) {
return {
siker: false,
hiba: 'Túl sok bejelentkezési kísérlet. Próbálja újra 5 perc múlva.',
};
}
// Bejelentkezési logika folytatása...
}
CSRF védelem és biztonsági fejlécek
Automatikus CSRF védelem
Jó hír: a Next.js 15 automatikus CSRF védelmet biztosít a Server Actionökhöz. Az Origin és Host fejlécek összehasonlításával gondoskodik arról, hogy a kérés a saját domainről érkezzen. De ettől függetlenül érdemes további védelmi rétegeket is beépíteni — a biztonsággal sosem lehet túlzásba esni.
// middleware.ts — Biztonsági fejlécek beállítása
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';
export function middleware(request: NextRequest) {
const valasz = NextResponse.next();
// Content Security Policy
valasz.headers.set(
'Content-Security-Policy',
[
"default-src 'self'",
"script-src 'self' 'unsafe-inline' 'unsafe-eval'",
"style-src 'self' 'unsafe-inline'",
"img-src 'self' data: https:",
"font-src 'self'",
"connect-src 'self'",
"frame-ancestors 'none'",
].join('; ')
);
// Egyéb biztonsági fejlécek
valasz.headers.set('X-Frame-Options', 'DENY');
valasz.headers.set('X-Content-Type-Options', 'nosniff');
valasz.headers.set('Referrer-Policy', 'strict-origin-when-cross-origin');
valasz.headers.set(
'Permissions-Policy',
'camera=(), microphone=(), geolocation=()'
);
valasz.headers.set(
'Strict-Transport-Security',
'max-age=63072000; includeSubDomains; preload'
);
return valasz;
}
Session kezelés és token biztonság
HttpOnly cookie-k használata
A munkamenet-tokenek biztonságos tárolása nem elhanyagolható kérdés. Mindig HttpOnly cookie-kat használjunk, amelyeket a JavaScript kód nem tud olvasni a böngészőben. Ez önmagában nem csodaszer, de jelentősen megnehezíti az XSS támadásokkal történő token-lopást.
// app/api/auth/bejelentkezes/route.ts — Biztonságos session beállítás
import { NextResponse } from 'next/server';
import { SignJWT } from 'jose';
export async function POST(request: Request) {
const { email, jelszo } = await request.json();
// Hitelesítés végrehajtása (egyszerűsített példa)
const felhasznalo = await hitelesites(email, jelszo);
if (!felhasznalo) {
return NextResponse.json(
{ hiba: 'Hibás email vagy jelszó' },
{ status: 401 }
);
}
// JWT token létrehozása
const titkosKulcs = new TextEncoder().encode(process.env.JWT_SECRET);
const token = await new SignJWT({
sub: felhasznalo.id,
email: felhasznalo.email,
role: felhasznalo.szerepkor,
})
.setProtectedHeader({ alg: 'HS256' })
.setIssuedAt()
.setExpirationTime('8h')
.sign(titkosKulcs);
// Biztonságos cookie beállítása
const valasz = NextResponse.json({ siker: true });
valasz.cookies.set('auth-token', token, {
httpOnly: true, // JavaScript nem éri el
secure: true, // Csak HTTPS-en keresztül
sameSite: 'lax', // CSRF védelem
maxAge: 8 * 60 * 60, // 8 óra
path: '/', // Minden útvonalra érvényes
});
return valasz;
}
Token frissítés és lejáratkezelés
Az automatikus token frissítés egy apró, de fontos részlet. Ha a token hamarosan lejár, a middleware csendben kiállít egy újat — a felhasználó észre sem veszi.
// middleware.ts — Automatikus token frissítés
import { NextResponse } from 'next/server';
import { jwtVerify, SignJWT } from 'jose';
export async function middleware(request: NextRequest) {
const token = request.cookies.get('auth-token')?.value;
if (!token) {
return NextResponse.next();
}
try {
const titkosKulcs = new TextEncoder().encode(process.env.JWT_SECRET);
const { payload } = await jwtVerify(token, titkosKulcs);
// Ha a token 2 órán belül lejár, frissítsük
const lejarat = (payload.exp ?? 0) * 1000;
const ketOraMultan = Date.now() + 2 * 60 * 60 * 1000;
if (lejarat < ketOraMultan) {
// Új token kiállítása
const ujToken = await new SignJWT({
sub: payload.sub,
email: payload.email,
role: payload.role,
})
.setProtectedHeader({ alg: 'HS256' })
.setIssuedAt()
.setExpirationTime('8h')
.sign(titkosKulcs);
const valasz = NextResponse.next();
valasz.cookies.set('auth-token', ujToken, {
httpOnly: true,
secure: true,
sameSite: 'lax',
maxAge: 8 * 60 * 60,
path: '/',
});
return valasz;
}
return NextResponse.next();
} catch {
// Érvénytelen token — törlés
const valasz = NextResponse.next();
valasz.cookies.delete('auth-token');
return valasz;
}
}
Biztonsági ellenőrzőlista Next.js alkalmazásokhoz
Végül itt egy átfogó ellenőrzőlista, amit érdemes végigfutni minden Next.js projekt indításakor (és időnként utána is).
Middleware és hitelesítés
- Frissítsd a Next.js-t legalább a 15.2.3-as verzióra a CVE-2025-29927 javítása érdekében
- Ne bízz kizárólag a middleware-re a hitelesítés terén
- Implementálj Data Access Layer mintát az adathozzáférés szintjén
- Minden Server Action önállóan ellenőrizze a jogosultságot
- Használj
josevagy hasonló könnyű könyvtárat JWT-kezeléshez az Edge Runtime-ban
Adatvalidálás
- Használj Zod-ot a Server Action bemenetek validálásához
- Soha ne bízz meg a kliens oldali validálásban — a szerver oldalon is ismételd meg
- Paraméteres SQL lekérdezéseket használj az SQL injection ellen
- Szűrd ki az érzékeny mezőket az adatbázis-lekérdezésekből (jelszó, token stb.)
HTTP biztonsági fejlécek
- Állíts be Content Security Policy-t (CSP)
- Engedélyezd a Strict-Transport-Security-t (HSTS)
- Használd az X-Frame-Options, X-Content-Type-Options fejléceket
- Konfiguráld a Referrer-Policy-t és a Permissions-Policy-t
Session és token kezelés
- Tárold a munkamenet-tokeneket HttpOnly, Secure cookie-kban
- Állíts be SameSite attribútumot a cookie-knál
- Implementálj automatikus token-frissítést
- Korlátozd a token élettartamát (maximum 8–24 óra)
Infrastruktúra
- Szűrd ki a
x-middleware-subrequestfejlécet a reverse proxy szintjén - Implementálj rate limitinget az API végpontokra és Server Actionökre
- Naplózd a gyanús tevékenységeket
- Rendszeresen frissítsd a függőségeket a biztonsági javítások érdekében
Összefoglalás és következő lépések
A Next.js middleware biztonsága 2026-ban már nem opcionális kérdés. A CVE-2025-29927 bebizonyította, hogy egyetlen védelmi rétegre építeni az alkalmazás biztonságát komoly következményekkel járhat. A mélységi védelmi stratégia alkalmazásával — edge/proxy szintű védelem, middleware, Data Access Layer és Server Action szintű jogosultságellenőrzés — robusztus és ellenálló biztonsági architektúrát építhetsz.
A legfontosabb elvek, amiket érdemes megjegyezni:
- Többrétegű védelem: Minden réteg önállóan is legyen képes a hitelesítés ellenőrzésére
- Zero Trust megközelítés: Soha ne feltételezd, hogy egy korábbi réteg már elvégezte az ellenőrzést
- Bemeneti validálás: Zod vagy hasonló könyvtárral minden Server Action bemenetét validáld
- Rendszeres frissítés: A Next.js és minden függőség naprakész tartása elengedhetetlen
Ezeknek az elveknek a következetes alkalmazásával a Next.js alkalmazásod nemcsak funkcionálisan, hanem biztonsági szempontból is a legmagasabb színvonalú lesz. Ha eddig nem foglalkoztál a mélységi védelemmel, most itt az ideje elkezdeni.