Sécuriser et configurer Strapi pour la production

Optimisez la sécurité, les middlewares et la configuration serveur pour un site robuste.

4 min read

Préparer l’environnement et les variables d’environnement

Avant tout, on définit nos variables sensibles dans un fichier .env. Strapi lit ces valeurs via env() :

Terminal
1
# .env
2
HOST=0.0.0.0
3
PORT=1337
4
APP_KEYS=key1,key2,key3
5
DATABASE_CLIENT=postgres
6
DATABASE_HOST=db.example.com
7
DATABASE_PORT=5432
8
DATABASE_NAME=strapi_prod
9
DATABASE_USERNAME=strapi
10
DATABASE_PASSWORD=supersecret
11
DATABASE_SSL=true
12
DATABASE_URL=postgres://strapi:supersecret@db.example.com:5432/strapi_prod
13
STRAPI_TOKEN=monTokenPourWebhooks
14
JWT_SECRET=unAutreSecretTresFort

Configurer le serveur Strapi

On place dans config/server.ts la lecture des variables :

config/server.ts
1
export default ({ env }) => ({
2
host: env('HOST', '0.0.0.0'),
3
port: env.int('PORT', 1337),
4
app: {
5
keys: env.array('APP_KEYS'), // ^? Clés de chiffrement pour les cookies et JWT
6
},
7
webhooks: {
8
defaultHeaders: {
9
Authorization: `Bearer ${env('STRAPI_TOKEN')}`, // ^? Protection des webhooks
10
},
11
},
12
});

Configurer la base de données avec SSL

Dans config/database.ts, on active SSL pour PostgreSQL/MySQL :

config/database.ts
1
import path from 'node:path';
2
3
export default ({ env }) => {
4
const client = env('DATABASE_CLIENT', 'sqlite');
5
const commonSsl = env.bool('DATABASE_SSL', false) && {
6
rejectUnauthorized: env.bool('DATABASE_SSL_REJECT_UNAUTHORIZED', true),
7
key: env('DATABASE_SSL_KEY', undefined),
8
cert: env('DATABASE_SSL_CERT', undefined),
9
ca: env('DATABASE_SSL_CA', undefined),
10
};
11
12
const connections = {
13
postgres: {
14
connection: {
15
connectionString: env('DATABASE_URL'),
16
ssl: commonSsl, // ^? Active SSL si DATABASE_SSL=true
17
},
18
pool: { min: 2, max: 10 },
19
},
20
// ... autres clients (mysql, sqlite)
21
};
22
23
return {
24
connection: { client, ...connections[client] },
25
};
26
};

Sécuriser les middlewares HTTP

On utilise le middleware strapi::security pour ajouter des headers HTTP via Helmet :

config/middlewares.ts
1
export default [
2
'strapi::errors',
3
{
4
name: 'strapi::security',
5
config: {
6
contentSecurityPolicy: {
7
directives: {
8
defaultSrc: ["'self'"], // ^? Limite les sources de scripts
9
scriptSrc: ["'self'"],
10
styleSrc: ["'self'", "'unsafe-inline'"],
11
imgSrc: ["'self'", 'data:'],
12
connectSrc: ["'self'"],
13
},
14
},
15
hsts: { maxAge: 31536000, includeSubDomains: true },
16
xssProtection: true,
17
frameguard: { action: 'deny' },
18
noSniff: true,
19
},
20
},
21
'strapi::cors',
22
'strapi::csrf',
23
'strapi::poweredBy',
24
'strapi::logger',
25
'strapi::query',
26
'strapi::body',
27
'strapi::favicon',
28
'strapi::public',
29
];

// @callout: Utilise strapi::cors et strapi::csrf pour bloquer // toute requête croisée non autorisée.

Limiter le nombre de requêtes (rate limiting)

On ajoute un middleware maison ou un plugin pour prévenir les DDoS :

config/plugins/rate-limit.ts
1
export default {
2
enabled: true,
3
config: {
4
policy: 'distributed',
5
points: 100, // 100 requêtes
6
duration: 60, // par minute
7
keyPrefix: 'rl:', // préfixe dans Redis (si utilisé)
8
},
9
};

Puis on l’injecte dans middlewares.ts :

config/middlewares.ts
1
@@
2
- 'strapi::logger',
3
+ 'strapi::logger',
4
+ { name: 'plugin::rate-limit', config: {} },

Sécuriser l’interface d’administration

  1. Change le chemin d’accès par défaut (/admin) :
    config/admin.ts
    1
    export default ({ env }) => ({
    2
    url: env('ADMIN_URL', '/secure-admin'), // ^? URL customisée
    3
    auth: {
    4
    secret: env('JWT_SECRET'),
    5
    },
    6
    });
  2. Active l’HTTPS sur ton proxy (Nginx, Traefik) :
    Terminal
    1
    # Exemple pour Traefik
    2
    labels:
    3
    - "traefik.http.routers.strapi-secured.rule=Host(`shop.example.com`)"
    4
    - "traefik.http.routers.strapi-secured.tls=true"

Déploiement avec Docker Compose

Exemple de fichier docker-compose.yml :

docker-compose.yml
1
version: '3.8'
2
services:
3
strapi:
4
image: strapi/strapi:5
5
env_file: .env
6
volumes:
7
- ./build:/srv/app/build
8
- ./config:/srv/app/config
9
ports:
10
- "${PORT}:${PORT}"
11
depends_on:
12
- db
13
db:
14
image: postgres:14
15
env_file: .env
16
volumes:
17
- db_data:/var/lib/postgresql/data
18
volumes:
19
db_data: {}

Surveillance et sauvegarde

  • Logs : redirige stdout/stderr vers un outil de monitoring (ELK, Datadog…).
  • Backups : planifie des dumps de ta base (pg_dump, mysqldump) et de /public/uploads.
  • Health check : configure un endpoint /health pour Kubernetes ou ton orchestrateur.

Récapitulatif des points clés

  • Lire les env via env() dans config/*.ts.
  • Chiffrer cookies et JWT avec APP_KEYS / JWT_SECRET.
  • Activer SSL sur la base de données et le reverse proxy.
  • Protéger les routes avec Helmet, CORS, CSRF et rate limiting.
  • Sécuriser l’admin en personnalisant l’URL et en forçant HTTPS.
  • Docker : séparer code, données et config, utiliser des secrets.

Exercices rapides

  1. Configurer un middleware
    Dans config/middlewares.ts, ajoute un header Referrer-Policy: no-referrer.
  2. Changer le chemin admin
    Modifie config/admin.ts pour que l’UI soit accessible sur /gestion.
  3. Tester le rate limiter
    Écris un script Bash qui envoie 200 requêtes à ton API en 30 s. Observe le comportement.

Liens utiles :