← Torna al blog
SicurezzaScanaris Team · 7 min di lettura · October 04, 2026

Checklist di sicurezza per la tua app Next.js prima del lancio

Lanciare un'app Next.js con Cursor, v0 o Bolt è veloce, ma la velocità nasconde falle che non vedi finché qualcuno non le trova al posto tuo. Questa checklist ripassa cosa controllare prima di premere deploy, con il perché di ogni punto, come verificarlo e il codice per correggerlo. Alla fine trovi la versione da due minuti.

Come Next.js traccia il confine tra server e client

Quasi tutte le falle di sicurezza in Next.js sono la stessa falla: qualcosa che doveva restare sul server è passato nel browser. I Server Components girano sul server e non inviano mai il loro codice al client; appena un file porta 'use client', tutto ciò che importa finisce nel bundle pubblico. I Route Handler (app/api/*/route.ts) e le Server Actions sono URL pubblici anche se non li vedi. Il middleware gira prima di tutto, ma non è una muraglia. Con quel confine chiaro, il resto della lista è meccanico.

1. Variabili d'ambiente: attenzione a NEXT_PUBLIC

Perché conta. Tutto ciò che inizia con NEXT_PUBLIC_ viene incorporato nel JavaScript del browser al momento della build. Chiunque può leggerlo con gli strumenti per sviluppatori. Non metterci mai una chiave API privata, un token di servizio né il segreto del tuo database.

Come verificare. Apri il tuo .env e la dashboard di Vercel e leggi ogni variabile con prefisso pubblico chiedendoti: succederebbe qualcosa se la pubblicassi su Twitter? Se la risposta è sì, toglile il prefisso e spostala sul server.

Come correggere. Le variabili senza prefisso esistono solo sul server: leggile da Server Components, Route Handler o Server Actions. Perché un modulo con segreti non possa mai essere importato da un componente client, aggiungi import 'server-only' nella prima riga: se qualcuno lo importa dal lato sbagliato, la build fallisce invece di far trapelare la chiave. Più dettagli in i segreti che la tua app fa trapelare nel browser.

2. Route Handler e Server Actions: valida e autorizza sempre

Perché conta. Una route API non è privata perché sta nella tua cartella. È un URL pubblico che chiunque può chiamare con curl. E una Server Action, anche se invocata da un pulsante, lo è altrettanto: Next.js la espone come endpoint POST con un identificativo. Un pulsante nascosto a un utente non impedisce a qualcuno di colpire l'endpoint direttamente.

Come correggere. Controlla la sessione e i permessi dentro ogni handler e ogni action, non solo nell'interfaccia. Valida il corpo della richiesta con uno schema (zod o simile) prima di toccare il database. Non accettare mai l'identificativo dell'utente dal client: prendilo dalla sessione. E metti un limite di richieste a ciò che costa denaro o invia email.

// app/actions/update-profile.ts
'use server'
import { z } from 'zod'
import { getSession } from '@/lib/auth'

const Schema = z.object({ name: z.string().min(1).max(80) })

export async function updateProfile(input: unknown) {
  const session = await getSession()
  if (!session) throw new Error('Unauthorized')
  const data = Schema.parse(input)
  // usa session.user.id, mai un id che arriva dal client
  await db.user.update({ where: { id: session.user.id }, data })
}

3. Il middleware non è la tua unica autenticazione

Perché conta. È allettante proteggere tutto /dashboard da middleware.ts e dimenticarsene. A marzo 2025 è stata pubblicata la CVE-2025-29927: un header interno (x-middleware-subrequest) permetteva di saltare completamente il middleware nelle versioni interessate, e con esso qualsiasi controllo di sessione che vivesse solo lì. È stata corretta in Next.js 15.2.3 e 14.2.25 (con patch per 13 e 12), ma la lezione resta.

Come correggere. Aggiorna Next.js a una versione corretta e usa il middleware come primo livello (reindirizzare chi non ha sessione), mai come l'unico. Il controllo che protegge davvero i dati va nella pagina, nell'handler o nell'action che li serve.

4. Header di sicurezza

Perché conta. Di default Next.js non invia header difensivi. Senza, la tua app è esposta a clickjacking, al fatto che il browser esegua come script ciò che non lo è e al downgrade a HTTP.

Come correggere. In next.config.js:

// next.config.js
const securityHeaders = [
  { key: 'Strict-Transport-Security', value: 'max-age=31536000; includeSubDomains' },
  { key: 'X-Frame-Options', value: 'SAMEORIGIN' },
  { key: 'X-Content-Type-Options', value: 'nosniff' },
  { key: 'Referrer-Policy', value: 'strict-origin-when-cross-origin' },
  { key: 'Permissions-Policy', value: 'camera=(), microphone=(), geolocation=()' },
]

module.exports = {
  poweredByHeader: false,
  productionBrowserSourceMaps: false,
  async headers() {
    return [{ source: '/(.*)', headers: securityHeaders }]
  },
}

La Content-Security-Policy merita un discorso a parte: Next.js inietta script inline per idratare la pagina, quindi una CSP rigorosa ha bisogno di un nonce generato nel middleware e passato ai componenti. Inizia in modalità Report-Only. Il dettaglio di ogni header è in gli header di sicurezza HTTP spiegati.

5. Segreti che passano nei Client Components

Perché conta. È facile che una chiave privata finisca in un componente client per errore, soprattutto quando l'IA riscrive file e sposta import. Se compare nel JavaScript servito, è già compromessa.

Come verificare. Dopo next build, cerca in .next/static stringhe come sk_live, service_role, sk-ant o URL di webhook. Se compaiono, ruotale e spostale sul server con import 'server-only' come rete di sicurezza.

6. Immagini remote e richieste a URL dell'utente

Perché conta. next/image ottimizza le immagini attraverso il tuo server. Se in images.remotePatterns permetti qualsiasi host, chiunque può usare il tuo server come proxy di immagini e consumare la tua quota. Lo stesso con una route API che scarica l'URL che l'utente le passa: può puntare a servizi interni della tua infrastruttura (SSRF).

Come correggere. Limita remotePatterns ai domini che usi davvero. Se una route deve scaricare URL esterni, valida il protocollo (solo https), rifiuta IP privati e nomi interni, e imposta un tempo massimo.

7. Redirect aperti

Perché conta. Il classico redirect(searchParams.next) dopo il login permette di costruire link del tuo dominio che finiscono su un sito di phishing: tuodominio.com/login?next=https://cattivo.example.

Come correggere. Accetta solo percorsi relativi che iniziano con / (e non con //), oppure confronta con una lista di destinazioni permesse.

8. File che non dovrebbero essere accessibili

Perché conta. Tutto ciò che sta in public/ viene servito così com'è: un .env copiato lì per errore, un dump del database o un service-account.json sono a un URL di distanza. E le source map in produzione permettono di leggere il tuo codice client con i nomi originali.

Come verificare. Prova tuodominio.com/.env, /.git/HEAD e apri un file JS del bundle per vedere se termina con una riga sourceMappingURL che punta a un .map raggiungibile. Guarda la cartella public/ con gli occhi di uno sconosciuto.

9. Cookie di sessione e librerie di autenticazione

Perché conta. Auth.js (NextAuth), Clerk o Supabase con il suo pacchetto server configurano bene i cookie di default. Quello che fallisce è ciò che aggiungi tu: un cookie tuo senza HttpOnly, un AUTH_SECRET debole o copiato da un tutorial, o la sessione salvata in localStorage.

Come correggere. Genera il segreto con openssl rand -base64 32, salvalo senza prefisso pubblico, e per qualsiasi cookie tuo usa Secure, HttpOnly e SameSite=Lax.

10. Dipendenze e versione di Next.js

Perché conta. La tua app si porta dietro centinaia di pacchetti, e Next.js stesso pubblica correzioni di sicurezza più volte l'anno. Il caso del middleware del 2025 ha colpito chi non aggiornava.

Come correggere. npm audit prima di ogni deploy, Dependabot o Renovate sul repository, e una regola semplice: aggiornare Next.js nello stesso mese in cui esce una patch di sicurezza.

Deploy su Vercel: tre dettagli

  • Ambienti. Le variabili hanno un ambito (Production, Preview, Development). Non dare ai deploy di preview le credenziali di produzione: una preview è un URL pubblico con il tuo codice più recente.
  • Protezione delle preview. Attiva la Deployment Protection perché gli URL di preview richiedano il login di Vercel; altrimenti chiunque abbia il link vede il branch in corso.
  • Header. Quelli di next.config.js si applicano su Vercel senza altro; se usi anche vercel.json, non duplicarli.

La tua checklist da 2 minuti

  • Nessuna variabile NEXT_PUBLIC_ contiene un segreto; i moduli con chiavi portano import 'server-only'.
  • Ogni Route Handler e Server Action controlla la sessione e valida l'input; l'id dell'utente viene dalla sessione.
  • Next.js in una versione corretta; il middleware non è l'unico livello di auth.
  • Header di sicurezza in next.config.js; poweredByHeader: false; CSP almeno in modalità report.
  • Bundle senza sk_live, service_role né webhook; source map disattivate.
  • remotePatterns limitati; nulla scarica URL dell'utente senza validazione.
  • Redirect solo verso percorsi relativi.
  • public/ senza file sensibili; .env e .git irraggiungibili.
  • Cookie con Secure, HttpOnly e SameSite; AUTH_SECRET casuale.
  • npm audit pulito; preview protette e senza segreti di produzione.

Verifica tutto questo in 30 secondi

Ripassare questa lista a mano a ogni deploy è noioso e si dimentica. Scanaris esegue controlli in sola lettura sul tuo sito pubblicato: header, segreti esposti nel JavaScript, file sensibili raggiungibili, source map, cookie e CORS. Ogni risultato arriva con un prompt pronto da incollare in Cursor o v0 con la correzione esatta per Next.js. Se lo lasci in monitoraggio, ti avvisa quando una sessione di vibe coding riapre qualcosa. Per approfondire il tuo stack, c'è la pagina di sicurezza per Next.js e la checklist generale di lancio.

Domande frequenti

Le Server Actions sono sicure di default?

Sono più comode di una route API, non più sicure. Next.js le espone come endpoint pubblici; l'autenticazione e la validazione le metti tu dentro ciascuna.

Il middleware protegge le mie route?

Serve per reindirizzare e per controlli economici, ma non deve essere l'unica barriera. Dopo il caso del 2025, la regola è controllare la sessione anche dove i dati vengono serviti.

Mi serve la CSP se uso Next.js?

Sì, ma con nonce, e iniziando in modalità report. Senza nonce, una CSP rigorosa blocca gli script inline del framework stesso e la pagina resta bianca.

Come se la cava il tuo sito?

Lascia che Scanaris lo analizzi e verifica in 30 secondi, gratis.

Scansiona il mio sito

Controlli correlati

Guide di sicurezza per stack