Sécuriser son code PHP : principes, bonnes pratiques et exemples
La sécurité applicative en PHP repose sur trois piliers :
1) Valider/neutraliser les entrées
2) Échapper les sorties
3) Maîtriser l’environnement d’exécution
1) Entrées : valider, filtrer, normaliser
- Toujours valider côté serveur (même si vous validez côté client).
- Utiliser des whitelists (valeurs permises) plutôt que des blacklists.
- Normaliser les formats (emails, dates, pays, etc.).
Code:
function sanitizeString(string $s): string { $s = trim($s); $s = preg_replace('/[\x00-\x1F\x7F]/u', '', $s); return $s; }
function validateEmail(string $email): bool { return filter_var($email, FILTER_VALIDATE_EMAIL) !== false; }
$input = sanitizeString($_POST['name'] ?? ''); if ($input === '' || mb_strlen($input) > 100) { http_response_code(400); exit('Invalid name'); }
2) Injections SQL : requêtes préparées obligatoires
Code:
$pdo = new PDO($dsn, $user, $pass, [ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_EMULATE_PREPARES => false, ]);
$stmt = $pdo->prepare('SELECT id, email FROM users WHERE email = :email'); $stmt->execute(['email' => $_POST['email']]); $user = $stmt->fetch(PDO::FETCH_ASSOC);
- Jamais de concaténation dans les requêtes (exemple : "... WHERE email='$email'").
- Avec ORM (Doctrine/Eloquent), utilisez les bindings natifs.
3) XSS : échapper les sorties
Code:
function e(string $s): string { return htmlspecialchars($s, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8'); } echo '' . e($user['display_name']) . '';
- HTML : htmlspecialchars avec ENT_QUOTES et UTF-8.
- JS inline : évitez d’injecter des données dans .
- URL : utilisez rawurlencode ou http_build_query.
4) CSRF : token anti-contrefaçon
Code:
// Génération session_start(); $_SESSION['csrf_token'] ??= bin2hex(random_bytes(32));
// Formulaire echo '';
// Validation if (!hash_equals($_SESSION['csrf_token'] ?? '', $_POST['csrf_token'] ?? '')) { http_response_code(403); exit('CSRF validation failed'); }
5) Authentification & mots de passe
Code:
$options = ['memory_cost' => 1<<18, 'time_cost' => 4, 'threads' => 2]; $hash = password_hash($password, PASSWORD_ARGON2ID, $options);
if (password_verify($inputPassword, $hash)) { if (password_needs_rehash($hash, PASSWORD_ARGON2ID, $options)) { $newHash = password_hash($inputPassword, PASSWORD_ARGON2ID, $options); } }
- Utilisez Argon2id (ou bcrypt si indisponible).
- Activez MFA et rate limiting.
6) Sessions sécurisées
Code:
session_set_cookie_params([ 'lifetime' => 0, 'path' => '/', 'domain' => '', 'secure' => true, 'httponly' => true, 'samesite' => 'Lax', ]); session_start(); session_regenerate_id(true);
7) Téléversement sécurisé
Code:
$finfo = new finfo(FILEINFO_MIME_TYPE); $mime = $finfo->file($_FILES['file']['tmp_name']); $allowed = ['image/jpeg', 'image/png', 'application/pdf'];
if (!in_array($mime, $allowed, true)) { http_response_code(400); exit('Type de fichier non autorisé'); }
8) En-têtes HTTP de sécurité
Code:
À configurer dans Apache/Nginx ou via header() en PHP
Header set X-Frame-Options "DENY" Header set X-Content-Type-Options "nosniff" Header set Referrer-Policy "no-referrer-when-downgrade" Header set Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" Header set Content-Security-Policy "default-src 'self'; script-src 'self'"
- X-Frame-Options : empêche le clickjacking.
- X-Content-Type-Options : bloque le MIME sniffing.
- Referrer-Policy : contrôle la fuite d’URL.
- Strict-Transport-Security : force HTTPS.
- Content-Security-Policy : limite les sources autorisées.
9) Configuration php.ini (Production)
Code:
expose_php = Off display_errors = Off log_errors = On error_reporting = E_ALL allow_url_fopen = Off allow_url_include = Off session.use_strict_mode = 1 session.cookie_secure = 1 session.cookie_httponly = 1 session.cookie_samesite = "Lax" disable_functions = "exec,passthru,shell_exec,system,proc_open,popen"
Configuration php.ini (Développement)
Code:
expose_php = Off display_errors = On display_startup_errors = On log_errors = On error_reporting = E_ALL html_errors = On
max_execution_time = 60 memory_limit = 512M
upload_max_filesize = 50M post_max_size = 60M
opcache.enable = 1 opcache.enable_cli = 1 opcache.validate_timestamps = 1 opcache.revalidate_freq = 2
session.use_strict_mode = 1 session.use_only_cookies = 1 session.cookie_secure = 0 session.cookie_httponly = 1 session.cookie_samesite = "Lax"
Checklists
Avant mise en production
- HTTPS obligatoire + HSTS.
- Cookies sécurisés (Secure, HttpOnly, SameSite).
- Audit Composer et dépendances.
- Scan DAST + SAST sans findings critiques.
En continu
- Mises à jour régulières (PHP, OS).
- Surveillance des logs.
- Tests de régression sécurité.