Vue d'ensemble de la sécurité
En-têtes de sécurité, CORS, validation des entrées, gestion des erreurs et checklist de production.
Vue d'ensemble
ScaleRocket suit les bonnes pratiques de sécurité à tous les niveaux -- base de données (RLS), API (Edge Functions) et client (gardes d'authentification). Cette page couvre l'architecture de sécurité et ce qu'il faut vérifier avant de passer en production.
Architecture de sécurité
Client (Browser)
├── Auth Guard (route protection)
├── Supabase client (anon key, JWT)
└── HTTPS only
│
Edge Functions (Server)
├── JWT validation
├── CORS headers
├── Input validation
├── Stripe signature verification
└── Service role (bypasses RLS)
│
Database (Supabase)
├── Row Level Security (RLS)
├── Triggers (server-side logic)
└── Functions (SECURITY DEFINER)En-têtes de sécurité
Le site marketing (apps/web) inclut des en-têtes de sécurité complets dans next.config.ts :
| En-tête | Valeur | Objectif |
|---|---|---|
X-Frame-Options | DENY | Empêche le clickjacking |
X-Content-Type-Options | nosniff | Empêche le reniflage de type MIME |
Referrer-Policy | strict-origin-when-cross-origin | Contrôle les informations de referrer |
X-DNS-Prefetch-Control | on | Active le DNS prefetching pour la performance |
Strict-Transport-Security | max-age=31536000; includeSubDomains | Force HTTPS pendant 1 an |
Permissions-Policy | camera=(), microphone=(), geolocation=() | Désactive les API navigateur inutilisées |
Content-Security-Policy | Voir ci-dessous | Empêche les attaques XSS et d'injection |
Content Security Policy (CSP)
L'en-tête CSP est l'en-tête de sécurité le plus important. Il indique au navigateur quelles sources de contenu sont autorisées :
// apps/web/next.config.ts
{
key: "Content-Security-Policy",
value: [
"default-src 'self'",
"script-src 'self' 'unsafe-inline' 'unsafe-eval' https://js.stripe.com https://*.supabase.co",
"style-src 'self' 'unsafe-inline' https://fonts.googleapis.com",
"font-src 'self' https://fonts.gstatic.com",
"img-src 'self' data: blob: https://*.supabase.co https://*.stripe.com",
"connect-src 'self' https://*.supabase.co https://api.stripe.com https://*.resend.com",
"frame-src https://js.stripe.com https://*.supabase.co",
"object-src 'none'",
"base-uri 'self'",
"form-action 'self'",
"frame-ancestors 'none'",
].join("; "),
}Personnaliser la CSP : Si vous ajoutez des scripts tiers (analytics, widgets de chat), ajoutez leurs domaines à la directive appropriée. Par exemple, pour autoriser Plausible analytics, ajoutez
https://plausible.ioàscript-srcetconnect-src.
Pour les applications Vite (apps/app, apps/ops), configurez ces en-têtes dans votre plateforme d'hébergement (configuration vercel.json ou headers de Vercel).
Configuration CORS
Les Edge Functions utilisent la variable d'environnement APP_URL pour le CORS, limitant les requêtes à votre domaine applicatif uniquement :
// supabase/functions/_shared/supabase.ts
const allowedOrigin = Deno.env.get("APP_URL") || "http://localhost:5173";
export const corsHeaders = {
"Access-Control-Allow-Origin": allowedOrigin,
"Access-Control-Allow-Headers":
"authorization, x-client-info, apikey, content-type",
};Définissez APP_URL dans vos secrets Supabase pour la production :
npx supabase secrets set APP_URL=https://app.yourdomain.comNote : La fonction
stripe-webhookutilise un gestionnaire CORS séparé car les webhooks Stripe n'envoient pas d'en-tête d'origine. La sécurité des webhooks repose sur la vérification de signature, pas sur le CORS.
Validation des entrées
Validez toutes les entrées dans les Edge Functions avant le traitement :
Deno.serve(async (req) => {
const { priceId, mode } = await req.json();
// Validate required fields
if (!priceId || typeof priceId !== "string") {
return new Response(
JSON.stringify({ error: "Invalid priceId" }),
{ status: 400 }
);
}
// Validate against allowed values
if (!["subscription", "payment"].includes(mode)) {
return new Response(
JSON.stringify({ error: "Invalid mode" }),
{ status: 400 }
);
}
// Proceed with validated data
});Gestion des erreurs
Ne jamais exposer les erreurs internes au client :
try {
// Function logic
} catch (error) {
// Log the full error server-side
console.error("Function failed:", error);
// Return a generic message to the client
return new Response(
JSON.stringify({ error: "An unexpected error occurred" }),
{ status: 500, headers: corsHeaders }
);
}Règles de sécurité clés
- Ne jamais exposer la clé service role dans
apps/webouapps/app. Elle est réservée àapps/opset aux Edge Functions. - Toujours activer le RLS sur les nouvelles tables. Une table sans RLS permet à quiconque possédant la clé anon de lire toutes les lignes.
- Toujours valider le JWT dans les Edge Functions protégées en utilisant le helper
getUser(). - Toujours vérifier les signatures des webhooks Stripe pour empêcher les événements falsifiés.
- Utiliser SECURITY DEFINER avec parcimonie. Les fonctions avec ce flag s'exécutent en tant que propriétaire (superuser), contournant le RLS.
Checklist de sécurité pour la production
Avant de déployer en production :
- RLS activé sur chaque table avec les politiques appropriées
- CORS restreint à vos domaines réels (pas
*) - Clé service role uniquement dans l'application admin et les secrets des Edge Functions
- Secret webhook Stripe défini dans les secrets Supabase
- En-têtes de sécurité configurés sur toutes les applications
- URLs de redirection OAuth restreintes à vos domaines dans le dashboard Supabase
- Templates d'e-mails personnalisés (pas de branding Supabase par défaut)
- Liste blanche admin mise à jour avec les vrais e-mails admin
- Rate limiting activé dans le dashboard Supabase
- Sauvegardes de base de données activées (plan Supabase Pro)
- Mode test Stripe basculé en mode live
- Variables d'environnement avec les valeurs de production (pas de clés de test)
Fini ? Marquez cette page comme terminée.