Aller au contenu

Sécurité

Toutes les plateformes de l'écosystème reposent sur un même socle de sécurité. Cette page définit ce socle : lorsque vous ajoutez une plateforme, considérez ces points comme des exigences, non des options.

Défense en profondeur

Les couches s'empilent selon le principe qu'aucune ne suffit à elle seule :

Couche Protection
Edge (nginx) TLS, HSTS, rate limit, limite de taille du corps
Application (HTTP) En-têtes de sécurité, allow-list CORS, CSRF, timeouts
Application (logique) RBAC, contrôle des droits, validation des entrées
Base de données RLS, requêtes paramétrées
Audit Journal d'audit chaîné par hachage

Le jeton n'atteint jamais le JS client

Le modèle BFF (Backend-for-Frontend) est le fondement de la sécurité côté frontend.

Le navigateur ne s'adresse jamais directement au backend : il ne parle qu'à des routes Next.js du même domaine, qui font office de proxy depuis le serveur. Le jeton vit dans un cookie httpOnly.

Résultat : le XSS cesse d'être un vecteur de vol de jeton. Même en parvenant à exécuter du JavaScript, un attaquant n'atteint pas le jeton.

S'y ajoute une double protection CSRF : en-tête dédié et vérification d'origine.

En-têtes de sécurité

Sur chaque réponse :

En-tête Objectif
Content-Security-Policy Ferme le vecteur d'exécution du XSS
Strict-Transport-Security Impose HTTPS (HSTS)
Cross-Origin-Opener-Policy Isole des attaques inter-fenêtres
Cross-Origin-Embedder-Policy Contrôle les ressources externes
Cross-Origin-Resource-Policy Restreint l'usage externe des ressources

Le CORS fonctionne par allow-list — jamais *.

Row-Level Security de Postgres

L'isolation des données d'organisations et d'utilisateurs est appliquée au niveau de la base de données, et non par une clause WHERE dans le code applicatif.

Pourquoi : un seul WHERE user_id = ? oublié dans le code et les données fuitent. La RLS applique ce contrôle à toutes les requêtes, indépendamment des erreurs de codage.

Garde-fou d'applicabilité au démarrage

Au démarrage, l'application vérifie que la RLS est réellement active. Si une policy manque, ou si l'utilisateur de connexion a le droit de contourner la RLS, l'application refuse de démarrer.

Car une RLS silencieusement désactivée est le cas le plus dangereux de tous : tout paraît fonctionner normalement.

SQL

  • Requêtes paramétrées — pas de concaténation de chaînes.
  • Pas d'ORM — du SQL écrit à la main sur pgx. Chaque requête est visible.

Rate limits et timeouts

Protection
Rate limit d'authentification (strict) Chemins /login, /oauth, /auth, /api/auth
Rate limit général de l'application (souple) Les autres chemins
Rate limit d'API API publiques du type /v1/*
Timeouts du serveur HTTP read · write · idle · header — tous configurés
Limite de taille du corps Au niveau de l'edge

Les limites strictes uniquement sur l'authentification

Appliquer le rate limit strict de l'authentification à tous les chemins fait dépasser la limite aux prefetch RSC de Next.js, qui reçoivent alors des 503. La limite stricte ne porte donc que sur les chemins d'authentification, avec une limite souple ailleurs.

Gestion des secrets

  • Chiffrement des jetons — les jetons OAuth tiers (Google Drive, Dropbox, etc.) sont stockés chiffrés en AES-256-GCM.
  • Clés cryptographiques — dans des HSM ; le HSM sur site et le HSM cloud basculent l'un sur l'autre.
  • Secrets applicatifs — par variables d'environnement, jamais versionnés dans git.

Ne mettez pas de secrets dans le dépôt

Identifiants serveur, clés d'API, client secrets, PIN de HSM : rien de tout cela n'est jamais écrit dans un dépôt, un script ou de la documentation. Les scripts de déploiement n'acceptent les secrets que par variables d'environnement.

En cas d'exposition accidentelle : (1) effectuer immédiatement une rotation, (2) examiner les journaux d'accès, (3) migrer le secret vers un système de gestion de secrets.

Endpoints fermés en production

/metrics et /swagger exposent la structure interne et la liste des endpoints. En production, ils sont protégés par un bearer token.

Journal d'audit

Un journal chaîné par hachage et en ajout seul. Chaque enregistrement contient le hachage du précédent.

Ce que cela implique : aucun enregistrement intermédiaire ne peut être supprimé ou modifié — la chaîne se rompt et le contrôle d'intégrité échoue. Seuls les administrateurs le lisent, et une opération distincte permet d'en vérifier l'intégrité.

Signature et non-répudiation

Les actes aux conséquences juridiques exigent une signature PIN2 — l'authentification (PIN1) ne suffit pas. Voir Authentification et autorisations pour le détail.

La clé privée de signature est scindée par ECDSA à seuil 2-of-2 — aucune des parties ne peut signer seule.

Tests

  • Tests unitaires — logique métier et contrôles de droits.
  • Tests d'intégration testcontainers — avec de vrais PostgreSQL/Redis, qui éprouvent la RLS pour de bon.
  • Tests golden vector — compatibilité cryptographique au niveau du protocole.

Liste de contrôle sécurité

Avant la mise en production d'une nouvelle plateforme :

  • [ ] TLS + HSTS actifs, certificats renouvelés automatiquement
  • [ ] Tous les en-têtes de sécurité configurés (CSP · HSTS · COOP · COEP · CORP)
  • [ ] Allow-list CORS — pas de *
  • [ ] Rate limits : strict sur l'authentification, souple ailleurs
  • [ ] Tous les timeouts du serveur HTTP configurés
  • [ ] RLS active et garde-fou de démarrage opérationnel
  • [ ] Toutes les requêtes paramétrées
  • [ ] Jetons en cookies httpOnly, jamais accessibles au JS client
  • [ ] Double protection CSRF
  • [ ] /metrics et /swagger fermés
  • [ ] Journal d'audit alimenté, intégrité vérifiable
  • [ ] Secrets par variables d'environnement, absents du dépôt
  • [ ] Tests d'intégration éprouvant réellement la RLS