Feat/ci cd securisation infcdaal3 #1
+41
@@ -0,0 +1,41 @@
|
||||
# Politique de sécurité — CESIZen
|
||||
|
||||
## Versions supportées
|
||||
|
||||
| Version | Support sécurité |
|
||||
|---------|------------------|
|
||||
| 1.x | ✅ Oui |
|
||||
| < 1.0 | ❌ Non |
|
||||
|
||||
## Signaler une vulnérabilité
|
||||
|
||||
Toute faille de sécurité doit être signalée **de manière privée**, sans
|
||||
divulgation publique préalable :
|
||||
|
||||
1. Ouvrir un ticket **confidentiel** sur le dépôt Gitea, ou
|
||||
2. Contacter l'équipe à `security@cesizen.fr`.
|
||||
|
||||
Merci d'inclure : description, impact, étapes de reproduction et, si possible,
|
||||
une proposition de correctif.
|
||||
|
||||
**Délais d'engagement :**
|
||||
- Accusé de réception : sous 48 h
|
||||
- Évaluation de la gravité (CVSS) : sous 5 jours ouvrés
|
||||
- Correctif pour les failles critiques : sous 15 jours
|
||||
|
||||
## Mesures de sécurité en place
|
||||
|
||||
- Chiffrement des échanges via **HTTPS/TLS** (Let's Encrypt via Nginx Proxy Manager)
|
||||
- Hachage des mots de passe avec **bcrypt** (12 tours)
|
||||
- Authentification API par jetons **Laravel Sanctum**
|
||||
- En-têtes de sécurité HTTP (HSTS, CSP, X-Frame-Options…)
|
||||
- Protection **CSRF** native Laravel sur les formulaires
|
||||
- Requêtes préparées (Eloquent/PDO) contre les **injections SQL**
|
||||
- Audit automatisé des dépendances (`composer audit`, `npm audit`) dans la CI
|
||||
- Chiffrement des données de session et cookies `Secure` / `HttpOnly`
|
||||
|
||||
## Conformité RGPD
|
||||
|
||||
Les données à caractère personnel sont traitées conformément au RGPD :
|
||||
minimisation, droit à l'effacement (suppression de compte), consentement,
|
||||
et anonymisation des données statistiques.
|
||||
@@ -0,0 +1,55 @@
|
||||
# ══════════════════════════════════════════════════════════════
|
||||
# CESIZen — Modèle de configuration PRODUCTION
|
||||
# Copier en `.env` sur le serveur puis renseigner les valeurs.
|
||||
# ⚠️ Ne JAMAIS committer le .env réel (secrets, clés, mots de passe).
|
||||
# ══════════════════════════════════════════════════════════════
|
||||
|
||||
APP_NAME=CESIZen
|
||||
APP_ENV=production
|
||||
APP_KEY= # généré via `php artisan key:generate`
|
||||
APP_DEBUG=false # JAMAIS true en production (fuite d'infos)
|
||||
APP_URL=https://cesizen.sam-coffre.duckdns.org
|
||||
|
||||
APP_LOCALE=fr
|
||||
APP_FALLBACK_LOCALE=fr
|
||||
APP_FAKER_LOCALE=fr_FR
|
||||
|
||||
# ── Journalisation ────────────────────────────────────────────
|
||||
LOG_CHANNEL=stack
|
||||
LOG_STACK=daily # rotation quotidienne des logs
|
||||
LOG_LEVEL=warning # on ne loggue pas le debug en prod
|
||||
|
||||
# ── Base de données (MySQL/MariaDB en production) ─────────────
|
||||
DB_CONNECTION=mysql
|
||||
DB_HOST=cesizen-db
|
||||
DB_PORT=3306
|
||||
DB_DATABASE=cesizen
|
||||
DB_USERNAME=cesizen_app # compte applicatif à privilèges limités
|
||||
DB_PASSWORD= # mot de passe fort (gestionnaire de secrets)
|
||||
|
||||
# ── Sessions & cookies (durcissement) ─────────────────────────
|
||||
SESSION_DRIVER=database
|
||||
SESSION_LIFETIME=120
|
||||
SESSION_ENCRYPT=true # chiffrement des données de session
|
||||
SESSION_SECURE_COOKIE=true # cookie envoyé uniquement en HTTPS
|
||||
SESSION_HTTP_ONLY=true # cookie inaccessible au JavaScript (anti-XSS)
|
||||
SESSION_SAME_SITE=lax # protection CSRF renforcée
|
||||
|
||||
# ── Sécurité mots de passe ────────────────────────────────────
|
||||
BCRYPT_ROUNDS=12 # coût du hachage bcrypt
|
||||
|
||||
# ── Cache / File d'attente ────────────────────────────────────
|
||||
CACHE_STORE=database
|
||||
QUEUE_CONNECTION=database
|
||||
FILESYSTEM_DISK=local
|
||||
|
||||
# ── Mail (notifications, réinitialisation de mot de passe) ────
|
||||
MAIL_MAILER=smtp
|
||||
MAIL_HOST=
|
||||
MAIL_PORT=587
|
||||
MAIL_USERNAME=
|
||||
MAIL_PASSWORD=
|
||||
MAIL_FROM_ADDRESS="no-reply@cesizen.fr"
|
||||
MAIL_FROM_NAME="${APP_NAME}"
|
||||
|
||||
VITE_APP_NAME="${APP_NAME}"
|
||||
@@ -0,0 +1,68 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use Closure;
|
||||
use Illuminate\Http\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
/**
|
||||
* SecurityHeaders
|
||||
* ---------------
|
||||
* Ajoute les en-têtes HTTP de sécurité recommandés (OWASP Secure Headers)
|
||||
* à toutes les réponses de l'application.
|
||||
*
|
||||
* Ces en-têtes renforcent la protection contre :
|
||||
* - le clickjacking (X-Frame-Options)
|
||||
* - le MIME-sniffing (X-Content-Type-Options)
|
||||
* - les fuites de référent (Referrer-Policy)
|
||||
* - le vol de session sur HTTP (Strict-Transport-Security / HSTS)
|
||||
* - certaines injections de contenu (Content-Security-Policy)
|
||||
*/
|
||||
class SecurityHeaders
|
||||
{
|
||||
public function handle(Request $request, Closure $next): Response
|
||||
{
|
||||
/** @var Response $response */
|
||||
$response = $next($request);
|
||||
|
||||
// Empêche l'affichage du site dans une iframe (anti-clickjacking)
|
||||
$response->headers->set('X-Frame-Options', 'SAMEORIGIN');
|
||||
|
||||
// Empêche le navigateur de "deviner" le type MIME d'un fichier
|
||||
$response->headers->set('X-Content-Type-Options', 'nosniff');
|
||||
|
||||
// Limite les informations de référent envoyées vers l'extérieur
|
||||
$response->headers->set('Referrer-Policy', 'strict-origin-when-cross-origin');
|
||||
|
||||
// Désactive des API navigateur sensibles non utilisées par l'app
|
||||
$response->headers->set(
|
||||
'Permissions-Policy',
|
||||
'geolocation=(), microphone=(), camera=(), payment=()'
|
||||
);
|
||||
|
||||
// HSTS : force le navigateur à n'utiliser que HTTPS pendant 1 an.
|
||||
// Uniquement sur connexion sécurisée (le reverse proxy NPM termine le TLS).
|
||||
if ($request->isSecure()) {
|
||||
$response->headers->set(
|
||||
'Strict-Transport-Security',
|
||||
'max-age=31536000; includeSubDomains'
|
||||
);
|
||||
}
|
||||
|
||||
// Content-Security-Policy : restreint les sources de contenu autorisées.
|
||||
// 'unsafe-inline' est toléré pour les styles/scripts Blade + Filament.
|
||||
$response->headers->set(
|
||||
'Content-Security-Policy',
|
||||
"default-src 'self'; "
|
||||
."img-src 'self' data: https:; "
|
||||
."script-src 'self' 'unsafe-inline' 'unsafe-eval'; "
|
||||
."style-src 'self' 'unsafe-inline' https:; "
|
||||
."font-src 'self' data: https:; "
|
||||
."connect-src 'self'; "
|
||||
."frame-ancestors 'self'"
|
||||
);
|
||||
|
||||
return $response;
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
<?php
|
||||
|
||||
use App\Http\Middleware\SecurityHeaders;
|
||||
use Illuminate\Foundation\Application;
|
||||
use Illuminate\Foundation\Configuration\Exceptions;
|
||||
use Illuminate\Foundation\Configuration\Middleware;
|
||||
@@ -12,7 +13,13 @@ return Application::configure(basePath: dirname(__DIR__))
|
||||
health: '/up',
|
||||
)
|
||||
->withMiddleware(function (Middleware $middleware): void {
|
||||
//
|
||||
// L'application est servie derrière un reverse proxy (Nginx Proxy Manager)
|
||||
// qui termine le TLS : on lui fait confiance pour détecter HTTPS,
|
||||
// l'IP réelle du client et le bon schéma d'URL.
|
||||
$middleware->trustProxies(at: '*');
|
||||
|
||||
// En-têtes de sécurité HTTP appliqués à toutes les réponses.
|
||||
$middleware->append(SecurityHeaders::class);
|
||||
})
|
||||
->withExceptions(function (Exceptions $exceptions): void {
|
||||
//
|
||||
|
||||
Reference in New Issue
Block a user