Tous
28 août 202418 minSécurité

Sécurité des applications web modernes : OWASP Top 10 2024

DR

Équipe Dev Ring

OWASP 2024

Validation d'entrée et sérialisation

Valider côté serveur et côté client, puis sérialiser strictement les sorties.

Validation avec Zod dans une Server Action

ts
'use server'
import { z } from 'zod'
import { db } from '@/lib/db'
import { revalidatePath } from 'next/cache'

const schema = z.object({
  title: z.string().min(3).max(120),
  content: z.string().min(1),
})

export async function createSecurePost(formData: FormData) {
  const parsed = schema.safeParse({
    title: formData.get('title'),
    content: formData.get('content'),
  })
  if (!parsed.success) throw new Error('Invalid input')
  await db.post.create({ data: parsed.data })
  revalidatePath('/posts')
}

Protection contre l'injection

Utiliser des requêtes paramétrées et échapper systématiquement les sorties HTML.

Requêtes paramétrées (exemple Prisma)

ts
// ⚠️ Anti-pattern (concaténation)
// await prisma.$queryRawUnsafe(`SELECT * FROM users WHERE email = '${email}'`)

// ✅ Paramétré
const users = await prisma.$queryRaw`SELECT * FROM users WHERE email = ${email}`

Authentification, sessions et cookies

Appliquer des attributs sécurisés et des durées limitées.

Cookies HttpOnly/secure + SameSite

ts
import { cookies } from 'next/headers'
import { serialize } from 'cookie'

export function setSessionCookie(token: string) {
  cookies().set(
    'session',
    token,
    {
      httpOnly: true,
      secure: true,
      sameSite: 'lax',
      maxAge: 60 * 60, // 1h
      path: '/',
    }
  )
}

En-têtes de sécurité

Configurer CSP, HSTS et autres en-têtes au niveau de la plateforme.

next.config.js — en-têtes de sécurité (Edge ou Node)

ts
// next.config.js
/** @type {import('next').NextConfig} */
const nextConfig = {
  async headers() {
    return [
      {
        source: '/(.*)',
        headers: [
          { key: 'Strict-Transport-Security', value: 'max-age=63072000; includeSubDomains; preload' },
          { key: 'X-Content-Type-Options', value: 'nosniff' },
          { key: 'X-Frame-Options', value: 'DENY' },
          { key: 'Referrer-Policy', value: 'strict-origin-when-cross-origin' },
          { key: 'Permissions-Policy', value: 'camera=(), microphone=(), geolocation=()' },
          { key: 'Content-Security-Policy', value: "default-src 'self'; img-src 'self' data:; script-src 'self'; style-src 'self' 'unsafe-inline'" },
        ],
      },
    ]
  },
}
module.exports = nextConfig

CSRF et SameSite

Protéger les mutations par un jeton et valider l'origine/referer.

CSRF token dans une Server Action

ts
'use server'
import { cookies, headers } from 'next/headers'

export async function mutateWithCsrf(formData: FormData) {
  const token = formData.get('csrf_token')
  const cookie = cookies().get('csrf')?.value
  const origin = headers().get('origin')

  if (!token || token !== cookie) throw new Error('CSRF invalid')
  if (!origin?.startsWith('https://votre-domaine.tld')) throw new Error('Origin invalid')

  // ... mutation
}

Stockage de secrets

Isoler les secrets dans le gestionnaire de secrets, jamais dans le code ou les logs.

Exemples d’injection de secrets en CI

bash
# GitHub Actions
echo "API_KEY=${{ secrets.API_KEY }}" >> $GITHUB_ENV

# Vercel
# vercel env add API_KEY production
# vercel env pull .env.local

CI/CD sécurisé

Intégrer SCA/SAST/DAST, signatures d’artefacts et approbations manuelles.

Pipeline DevSecOps (extrait)

yaml
jobs:
  build:
    steps:
      - uses: actions/checkout@v4
      - run: npm ci
      - run: npm audit --audit-level=high
      - name: CodeQL
        uses: github/codeql-action/analyze@v3
      - name: Container scan
        uses: aquasecurity/trivy-action@0.18.0
  deploy:
    needs: [build]
    environment: production
    steps:
      - name: Approvals
        uses: some/action-manual-approval@v1

Journalisation et détection

Mettre en place des logs structurés, corrélables et compatibles SIEM.

Logger structuré et PII-safe

ts
import pino from 'pino'
const logger = pino({ level: 'info', redact: ['req.headers.authorization', 'user.email'] })

export function logRequest(req: { id: string; path: string; ip: string }) {
  logger.info({ reqId: req.id, path: req.path, ip: req.ip }, 'http_request')
}

Conclusion

La réduction de la surface d’attaque combine hygiène de code, configuration robuste et automatisation DevSecOps. Les extraits ci-dessus constituent une base opérationnelle pour aligner vos pratiques sur l’OWASP Top 10 2024.