Als je met Cursor, v0 of Lovable een Next.js app bouwt, genereert de AI code die werkt — maar niet automatisch code die veilig is. Ik heb honderden AI-gegenereerde Next.js apps gescand en dezelfde 5 beveiligingsfouten zien terugkomen.
In dit artikel deel ik de exacte stappen die ik zelf gebruik om elke Next.js app te beveiligen, in slechts 10 minuten. Geen enterprise tooling, geen security diploma nodig.
⚡ TL;DR — Wat je gaat leren
- ✅ HTTPS forceren met HSTS headers
- ✅ Content Security Policy implementeren tegen XSS
- ✅ API routes beveiligen met authenticatie
- ✅ Environment variables veilig configureren
- ✅ Beveiliging automatiseren met monitoring
Tijd: 10 minuten | Niveau: Beginner → Intermediate
📋 Inhoudsopgave
Waarom Dit Nu Belangrijker Is Dan Ooit
Als indie developers bewegen we snel. We scaffolden met create-next-app, voegen auth toe, koppelen een database, en deployen naar Vercel voor de lunch. Maar snelheid creëert blinde vlekken.
Het probleem: In 2026 scannen aanvallers elke deployed app op het internet met geautomatiseerde tools. Je hoeft geen Fortune 500 bedrijf te zijn om doelwit te worden — je hoeft alleen maar vindbaar te zijn.
Het goede nieuws? Je kunt je app in 10 minuten significant veiliger maken. Geen enterprise tooling. Geen security diploma nodig.
⏱️ De 10-Minuten Beveiligingscheck
🔒 Stap 1: Forceer HTTPS en HSTS (0-2 minuten)
Zorg dat al je verkeer versleuteld is. In Next.js op Vercel gebeurt dit vaak automatisch, maar je moet de Strict-Transport-Security header handmatig toevoegen voor maximale veiligheid.
Waarom dit belangrijk is
HSTS (HTTP Strict Transport Security) dwingt browsers af om altijd HTTPS te gebruiken, zelfs als een gebruiker http:// typt. Dit voorkomt:
- Man-in-the-middle attacks
- SSL stripping attacks
- Mixed content warnings
De implementatie
// next.config.js
/** @type {import('next').NextConfig} */
const nextConfig = {
async headers() {
return [
{
source: '/(.*)',
headers: [
{
key: 'Strict-Transport-Security',
value: 'max-age=63072000; includeSubDomains; preload'
// 2 jaar, inclusief subdomeinen, eligible voor HSTS preload list
}
]
}
];
}
};
module.exports = nextConfig;
💡 Pro Tip: De preload directive maakt je domein eligible voor de HSTS preload list van browsers. Hierdoor weet elke moderne browser al voor de eerste connectie dat je site HTTPS-only is.
🛡️ Stap 2: Implementeer een Content Security Policy (2-5 minuten)
Dit is je belangrijkste wapen tegen XSS (Cross-Site Scripting). Een CSP vertelt de browser precies welke bronnen geladen mogen worden.
Het XSS probleem
Zonder CSP kan een aanvaller die erin slaagt om JavaScript te injecteren:
- Gebruikerssessies hijacken
- Formulieren onderscheppen
- Malware verspreiden
CSP in Next.js via Middleware
Voor Next.js raden we aan om CSP via middleware te implementeren. Dit stelt je in staat om nonces te gebruiken voor inline scripts — de modernste en veiligste aanpak.
// middleware.ts
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';
export function middleware(request: NextRequest) {
const nonce = Buffer.from(crypto.randomUUID()).toString('base64');
const cspHeader = `
default-src 'self';
script-src 'self' 'nonce-${nonce}' 'strict-dynamic';
style-src 'self' 'nonce-${nonce}';
img-src 'self' blob: data:;
font-src 'self';
object-src 'none';
base-uri 'self';
form-action 'self';
frame-ancestors 'none';
upgrade-insecure-requests;
`.replace(/\s{2,}/g, ' ').trim();
const requestHeaders = new Headers(request.headers);
requestHeaders.set('Content-Security-Policy', cspHeader);
requestHeaders.set('X-Nonce', nonce);
const response = NextResponse.next({
request: { headers: requestHeaders }
});
response.headers.set('Content-Security-Policy', cspHeader);
return response;
}
export const config = {
matcher: [
'/((?!_next/static|_next/image|favicon.ico|.*\.svg$).*)'
]
};
⚠️ Waarschuwing: Test je CSP eerst in Content-Security-Policy-Report-Only modus. Een te strikte CSP kan je site breken. Gebruik de browser console om policy violations te debuggen.
💡 Next.js Tip: Het gebruik van nonces in middleware werkt perfect voor dynamische pagina's. Maar let op: als je SSG/ISR gebruikt, wordt de pagina de-optimaliseerd naar dynamisch omdat elke request een unieke nonce krijgt. Voor static exports, overweeg hash-based CSP als alternatief.
Klaar-toegang CSP Generator
Geen zin om dit zelf te schrijven? Draai een scan op Shadow Guard en kopieer onze kant-en-klare CSP-prompt voor Next.js — afgestemd op jouw specifieke app configuratie.
🔐 Stap 3: Beveilig je API Routes (5-7 minuten)
Next.js API routes zijn standaard openbaar. Dit is de meest gemaakte fout die we zien: de UI is beschermd met middleware auth, maar de onderliggende API route staat wijd open.
Het kwetsbare patroon
// app/api/users/route.ts — ❌ GEEN AUTH CHECK
import { db } from '@/lib/db';
export async function GET() {
const users = await db.user.findMany();
return Response.json(users); // Iedereen kan dit endpoint aanroepen!
}
Iedereen kan nu curl https://jouwapp.com/api/users uitvoeren en je volledige gebruikersdatabase dumpen.
Het veilige patroon
// app/api/users/route.ts — ✅ AUTH CHECK TOEGEVOEGD
import { db } from '@/lib/db';
import { auth } from '@/lib/auth';
export async function GET() {
const session = await auth();
if (!session?.user) {
return Response.json({ error: 'Unauthorized' }, { status: 401 });
}
// Scope de query tot de geauthenticeerde gebruiker!
const users = await db.user.findMany({
where: { organizationId: session.user.orgId }
});
return Response.json(users);
}
✅ Best Practice: Gebruik altijd authorization + scoping. Niet alleen checken of iemand is ingelogd, maar ook of ze toegang hebben tot deze specifieke data.
Snelle check: Vind onbeschermde routes
# Vind API routes die geen auth functie bevatten
grep -rL "auth\|getSession\|getServerSession\|currentUser" app/api/*/route.ts
Elk bestand dat dit commando teruggeeft, is een route zonder auth check. Review ze één voor één.
🔑 Stap 4: Check je Environment Variables (7-9 minuten)
Dit is de #1 oorzaak van beveiligingslekken in Next.js apps. De regel is simpel:
Elke env variabele met NEXT_PUBLIC_ prefix wordt naar de browser gestuurd. De rest blijft op de server.
De 30-seconden check
grep -r "NEXT_PUBLIC_" .env* --include=".env*"
Vraag jezelf af: staat er iets geheims in die lijst? Database URLs, API keys met schrijfrechten, auth secrets — niets hiervan mag ooit NEXT_PUBLIC_ zijn.
Automatische leak detectie
#!/bin/bash
# check-env-leaks.sh — Vlag verdachte NEXT_PUBLIC_ variabelen
SUSPICIOUS_PATTERNS="SECRET|KEY|PASSWORD|TOKEN|DATABASE|PRIVATE|AUTH"
echo "🔍 Scannen op mogelijk gelekte env variabelen..."
grep -rE "NEXT_PUBLIC_.*($SUSPICIOUS_PATTERNS)" .env* 2>/dev/null | while read -r line; do
echo "⚠️ MOGELIJK LEK: $line"
done
echo "✅ Scan voltooid."
⚠️ Critical: Als dit script output genereert, fix het onmiddellijk. Hernoem de variabele zonder de NEXT_PUBLIC_ prefix en verplaats de logica naar een Server Component of API route.
| ❌ Fout | ✅ Correct |
|---|---|
NEXT_PUBLIC_STRIPE_SECRET_KEY |
STRIPE_SECRET_KEY (server only) |
NEXT_PUBLIC_DATABASE_URL |
DATABASE_URL (server only) |
NEXT_PUBLIC_AUTH_SECRET |
AUTH_SECRET (server only) |
🤖 Stap 5: Automatiseer de Controle (9-10 minuten)
De laatste minuut gebruik je om een systeem op te zetten dat dit voor je blijft controleren. Beveiliging is geen eenmalige actie, maar een proces.
Wat je moet monitoren
| Controle | Frequentie | Tool |
|---|---|---|
| Dependency vulnerabilities | Elke push | npm audit in CI |
| SSL certificaat verval | Dagelijks | SSL monitor |
| CSP violations | Real-time | Reporting API |
| Nieuwe CVEs | Dagelijks | Automatische alerts |
Automatische Dependency Updates
Naast npm audit in CI, raden we aan om Dependabot of Renovate te configureren voor geautomatiseerde PR's bij nieuwe security updates:
# .github/dependabot.yml
version: 2
updates:
- package-ecosystem: "npm"
directory: "/"
schedule:
interval: "daily"
open-pull-requests-limit: 10
labels:
- "dependencies"
- "security"
CI/CD integratie
# .github/workflows/security.yml
name: Security Audit
on: [push, pull_request]
jobs:
audit:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
- run: npm ci
- run: npm audit --audit-level=high
# Voeg Shadow Guard scanning toe
shadowguard:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Shadow Guard Scan
run: npx @shadowguard/cli scan --ci
env:
SHADOWGUARD_TOKEN: ${{ secrets.SHADOWGUARD_TOKEN }}
🎯 Bonus: Rate Limiting (Extra 2 minuten)
Een veelvoorkomende Next.js kwetsbaarheid in 2026 is het ontbreken van rate limiting. Zonder rate limiting kan een aanvaller je API overbelasten of brute-force aanvallen uitvoeren, wat leidt tot hoge serverkosten of datalekken.
Het probleem
// ❌ Kwetsbaar voor brute-force aanvallen
export async function POST(req: Request) {
const { email, password } = await req.json();
const user = await authenticate(email, password);
return Response.json({ success: !!user });
}
De oplossing met Upstash
// ✅ Beveiligd met rate limiting
import { Ratelimit } from '@upstash/ratelimit';
import { Redis } from '@upstash/redis';
const ratelimit = new Ratelimit({
redis: Redis.fromEnv(),
limiter: Ratelimit.slidingWindow(5, '1 m'), // 5 requests per minuut
});
export async function POST(req: Request) {
const ip = req.headers.get('x-forwarded-for') ?? '127.0.0.1';
const { success } = await ratelimit.limit(ip);
if (!success) {
return Response.json(
{ error: 'Te veel pogingen. Probeer het later opnieuw.' },
{ status: 429 }
);
}
const { email, password } = await req.json();
const user = await authenticate(email, password);
return Response.json({ success: !!user });
}
💡 Tip: Voor een complete guide over security hardening in Next.js, zie ook onze 10-minuten beveiligingsgids.
📋 De 10-Minuten Checklist
| Minuut | Actie | Commando/Link |
|---|---|---|
| 0-2 | HTTPS + HSTS configureren | next.config.js aanpassen |
| 2-5 | CSP implementeren | CSP Generator |
| 5-7 | API routes beveiligen | auth() check toevoegen |
| 7-9 | Env variables checken | grep -r "NEXT_PUBLIC_" .env* |
| 9-10 | Automatisering opzetten | Start monitoring |
| +2 min | Bonus: Rate limiting toevoegen | Upstash configureren |
🚀 Volgende Stappen: Van Basis naar Bulletproof
De stappen hierboven elimineren de meest voorkomende aanvalsvectoren. Maar echte wereld vulnerabilities zijn subtieler:
- SQL injection via geneste query parameters
- Prototype pollution via server action payloads
- SSRF via image optimization URLs
- IDOR (Insecure Direct Object Reference) in API routes
Deze vereisen geautomatiseerde, context-aware scanning die Next.js begrijpt op framework niveau.
Shadow Guard Monitoring
Met Shadow Guard Monitoring scannen we je Next.js app elke dag op:
- ✅ Nieuwe kwetsbaarheden
- ✅ Verlopende SSL-certificaten
- ✅ Misconfiguraties
- ✅ Dependency CVEs
- ✅ API route exposures
Zo kun jij blijven bouwen, terwijl wij de wacht houden.
"Shadow Guard vond 3 open API routes in mijn Next.js app die ik totaal over het hoofd had gezien. Binnen 5 minuten had ik ze gepatched. Dit tool is een must-have voor elke indie hacker."
🛡️ Wil je een volledige security check?
Ontdek wat je Next.js app blootlegt aan het internet. Onze gratis scan analyseert:
- 14+ beveiligingsheaders (CSP, HSTS, X-Frame-Options)
- API route beveiliging & authenticatie
- SSL/TLS configuratie & certificaat geldigheid
- Dependency vulnerabilities (CVE scanning)
- Environment variable leaks
✓ Geen credit card nodig • ✓ Resultaten in 30 seconden • ✓ AI-fix prompts inbegrepen
Veelgestelde Vragen (FAQ)
Is CSP echt nodig als ik al XSS filtering heb?
Ja. Browser XSS filters (zoals XSS Auditor) zijn inmiddels grotendeels verwijderd omdat ze juist nieuwe aanvalsvectoren introduceerden. CSP is de moderne standaard en wordt actief ondersteund door alle browsers.
Werkt dit ook voor Next.js Pages Router?
De meeste principes zijn identiek. CSP implementatie verschilt licht — je kunt getInitialProps gebruiken in _document.tsx of middleware (vanaf Next.js 12.2).
Hoe vaak moet ik deze check herhalen?
- Manueel: Maandelijks, of na elke major dependency update
- Geautomatiseerd: Laat het dagelijks lopen via CI/CD
Wat als npm audit vulnerabilities rapporteert?
- Check of je de vulnerable dependency direct gebruikt
- Zoek naar een patched versie:
npm update <package> - Als er geen fix is, overweeg een alternatief
- Gebruik
overridesinpackage.jsonals tijdelijke fix
Gerelateerde Artikelen
Build fast. Ship often. But scan before you sleep. 🛡️