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.

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 Editorial Team

Our team of expert writers and editors.