eduardweb.
Securitate & AuthIntermediar#nextjs#securitate#web-dev#owasp

OWASP Top 10 în Next.js: La ce mă uit în PR-uri în 2026

De Ioan Manole, 23 mai 2026 · 8 vizualizări · 2 like-uri

Postat 23 mai 2026
typescript
/* server-action.ts */
'use server';

import { db } from '@/db';
import { auth } from '@/auth';
import { z } from 'zod';

const deletePostSchema = z.object({ id: z.string().uuid() });

export async function deletePost(rawData: unknown) {
  const session = await auth();
  if (!session?.user) throw new Error('Neautorizat');

  const parsed = deletePostSchema.safeParse(rawData);
  if (!parsed.success) throw new Error('Date invalide');

  // Verificăm explicit dacă userul deține resursa, nu doar dacă e logat!
  return db.post.delete({
    where: {
      id: parsed.data.id,
      authorId: session.user.id
    },
  });
}

Să fim sinceri: Next.js în 2026 ne-a făcut viața mult mai ușoară, dar a mutat și linia frontului în securitate direct în componentele noastre de frontend. Dacă pe vremuri aveai o barieră clară între backend și client, acum granița e atât de fină încât e extrem de ușor să scapi chestii grave în producție.

La un proiect recent cu peste 15.000 de utilizatori activi, am fost puși în situația de a face un audit rapid de securitate după ce un tool de scanare automată a început să urle. Am realizat atunci că echipa se baza mult prea mult pe magia din spatele Next.js, ignorând chestii de bază din OWASP Top 10.

Server Actions și mitul protecției automate

Cea mai mare capcană în care cad developerii de Next.js este să creadă că Server Actions sunt securizate implicit împotriva CSRF sau a accesului neautorizat. Da, Next.js folosește headere speciale ca să prevină execuțiile cross-site arbitrare, dar asta nu înseamnă că acțiunea ta e protejată dacă nu verifici manual cine o apelează.

Am văzut zeci de PR-uri unde o acțiune de tipul deleteComment(id) presupunea că, dacă utilizatorul a ajuns pe acea pagină, înseamnă că are și dreptul să șteargă comentariul. Un atacator poate simula apelul de Server Action extrem de simplu dacă știe ID-ul acțiunii (care e public în build-ul de client).

Trade-off-ul aici e simplu: Server Actions îți oferă un DX genial și viteză de dezvoltare, dar te obligă să scrii cod de autorizare repetitiv în fiecare funcție expusă. Dacă uiți o singură linie de validare a sesiunii, ai lăsat o poartă deschisă în baza de date.

SQL Injection prin „scurtături” în ORM-uri

Folosim Prisma sau Drizzle și avem impresia că suntem imuni la SQL Injection. Teoretic, așa este, dar practic, când ai nevoie de un query mai complex și apelezi la raw SQL sau la template-uri dinamice, lucrurile scapă de sub control.

Am pățit ca un coleg să folosească sql.raw() din Drizzle pentru a face o căutare dinamică bazată pe un input din client. A concatenat direct string-ul în query în loc să folosească query-uri parametrizate. La PR am observat din greșeală, dar dacă trecea de review, era un SQL injection clasic, de manual, fix într-o aplicație modernă de Next.js.

Ce verific la fiecare PR de Next.js

Ca să nu ne mai prindem urechile la audituri, am introdus trei reguli stricte pe care le urmăresc la fiecare review:

  1. Verificarea contextului de rulare: Orice Server Action trebuie să înceapă cu verificarea sesiunii și validarea input-ului prin Zod. Fără excepții.
  2. Izolarea codului de server: Folosim pachetul server-only în fișierele care interacționează cu baza de date sau cu chei API secrete. Altfel, riști ca Webpack să îți includă secretele în bundle-ul de client.
  3. Ieșirea din dangerouslySetInnerHTML: Dacă chiar trebuie să randăm HTML trimis de utilizatori, verific dacă string-ul respectiv trece printr-un utilitar de sanitizare precum isomorphic-dompurify înainte de afișare.

Voi cum gestionați autorizarea în Server Actions? Vă bazați pe un middleware custom sau scrieți verificările manual în fiecare acțiune?

Răspunsuri 0

Se încarcă răspunsurile…

Loghează-te pentru a răspunde

Doar membrii comunității pot lăsa comentarii.