Next.js Middleware Biztonság 2026: Mélységi Védelem és a CVE-2025-29927 Tanulságai

A CVE-2025-29927 bebizonyította: a middleware önmagában nem elég. Ismerd meg a mélységi védelmi stratégiákat, a Data Access Layer mintát és a Server Action biztonsági megoldásokat Next.js-ben, gyakorlati kódpéldákkal.

Next.js Middleware Biztonság 2026: Útmutató

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:

  1. Edge/Proxy réteg — Reverse proxy vagy CDN szintű védelmi szabályok
  2. Middleware réteg — Első szintű hitelesítés és átirányítás
  3. Server Component réteg — Adatlekérdezéseknél történő jogosultságellenőrzés
  4. Data Access Layer — Az adatbázis-hozzáférés szintjén végzett hitelesítés
  5. 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 jose vagy 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-subrequest fejlé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:

  1. Többrétegű védelem: Minden réteg önállóan is legyen képes a hitelesítés ellenőrzésére
  2. Zero Trust megközelítés: Soha ne feltételezd, hogy egy korábbi réteg már elvégezte az ellenőrzést
  3. Bemeneti validálás: Zod vagy hasonló könyvtárral minden Server Action bemenetét validáld
  4. 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.

A Szerzőről Hannah Lindqvist

Hannah is a performance-focused frontend engineer with nine years building React applications, the last five exclusively on Next.js. She spent three years at Spotify on the Web Player team optimizing TTI on low-end devices in emerging markets, then two years at a Stockholm-based e-commerce platform where she rebuilt the storefront on App Router and edge runtime, hitting sub-200ms TTFB across European POPs. She currently freelances for DTC brands and SaaS companies that need a Core Web Vitals rescue, and occasionally contributes patches to next/font and the Vercel Speed Insights SDK. She has presented at React Advanced London and React Summit Amsterdam on streaming rendering patterns. Her tutorials are the ones with Lighthouse screenshots and flame graphs, because she doesn't trust benchmarks she can't reproduce. Strong preference for Playwright over Cypress and Vitest over Jest.