Cybersécurité

Tutoriel : Les bonnes pratiques de sécurité pour les développeurs

10 min de lecture

Pourquoi le secure coding est plus rentable que tout audit a posteriori ?

Une faille corrigée en développement coûte 1×, en production elle coûte 100× — sans compter l’impact réputation et juridique. Au Sénégal, où beaucoup de PME développent en interne ou via freelances sans culture sécurité, le coût d’une seule injection SQL ou XSS découvertes après lancement peut atteindre des dizaines de millions de FCFA. Cet article applique l’OWASP Top 10 (2021) avec du code corrigé prêt à copier-coller.

La sécurité pour les développeurs : coder de façon sécurisée

La majorité des failles de sécurité proviennent du code applicatif. En tant que développeur, intégrer la sécurité dès le début du développement est bien plus efficace et moins coûteux que de corriger après coup.

Le coût des failles

  • Corriger une faille en développement : 1x le coût
  • Corriger en test : 6x
  • Corriger en production : 15x
  • Corriger après une brèche : 100x

Le Top 10 OWASP — les failles les plus critiques

Rang Faille Exemple concret
1 Broken Access Control Un utilisateur accède aux données d’un autre via l’URL
2 Cryptographic Failures Mots de passe stockés en clair dans la base
3 Injection (SQL, XSS) Données utilisateur insérées directement dans une requête SQL
4 Insecure Design Pas de limitation du nombre de tentatives de connexion
5 Security Misconfiguration Mode debug activé en production

Pratique 1 : Prévenir l’injection SQL

// DANGEREUX — ne jamais faire :

query = « SELECT * FROM users WHERE id =  » + userId;

// SÉCURISÉ — requête préparée :

query = « SELECT * FROM users WHERE id = ? »;

stmt = db.prepare(query);

stmt.execute([userId]);

Pratique 2 : Prévenir le XSS

// DANGEREUX :

élément.innerHTML = userInput;

// SÉCURISÉ :

élément.textContent = userInput;

// Ou utiliser DOMPurify pour du HTML :

élément.innerHTML = DOMPurify.sanitize(userInput);

Pratique 3 : Gérer les mots de passe

// JAMAIS : stockage en clair ou MD5/SHA1

password_hash = md5(password); // DANGEREUX

// TOUJOURS : bcrypt, scrypt ou Argon2

// Python :

from bcrypt import hashpw, gensalt

hashed = hashpw(password.encode(), gensalt())

// PHP (WordPress) :

$hash = wp_hash_password($password);

Pratique 4 : Sécuriser les API

  • Authentification par tokens JWT ou OAuth2
  • Rate limiting : limitez les requêtes par IP
  • Validation des entrées : vérifiez type, taille, format
  • HTTPS obligatoire : jamais d’API en HTTP
  • CORS : configurez les origines autorisées

Pratique 5 : Gestion des secrets

  • Ne mettez JAMAIS de clés API, mots de passe ou tokens dans le code source
  • Utilisez des variables d’environnement (.env)
  • Ajoutez .env à votre .gitignore
  • En production : utilisez un gestionnaire de secrets (Vault, AWS Secrets Manager)

Erreurs fréquentes (secure coding)

1. Concaténation SQL au lieu de requêtes préparées

Cause : on construit la requête en concatenant les variables. Tout payload utilisateur (1 OR 1=1 --) devient exploitable.

Solution : requêtes préparées TOUJOURS : $stmt = $pdo->prepare("SELECT * FROM users WHERE id = ?") puis $stmt->execute([$id]). Notez bien prepare/execute (anglais), pas préparé/exécuté.

2. innerHTML avec input utilisateur sans sanitize

Cause : div.innerHTML = userComment permet l’injection de <script>. XSS stockée immédiate.

Solution : textContent par défaut. Si du HTML est nécessaire, utilisez DOMPurify : div.innerHTML = DOMPurify.sanitize(userComment). Ne réinventez jamais le sanitize.

3. Hash de mot de passe avec MD5/SHA-1/SHA-256

Cause : on hashe les mots de passe avec MD5 ou SHA-256. Ces algos sont conçus pour être rapides — un GPU casse 10 milliards de hashs/seconde.

Solution : Argon2id (recommandé OWASP) ou bcrypt (work factor 12+). PHP : password_hash($pwd, PASSWORD_ARGON2ID). Python : argon2.PasswordHasher().hash(pwd). Node.js : argon2.hash(pwd).

4. .env committé dans Git

Cause : on push .env avec API keys, DB password, JWT secret. Les bots scannent GitHub en permanence et exploitent en quelques minutes.

Solution : .gitignore systématique pour .env + Gitleaks en pre-commit. Si déjà committé : rotation IMMÉDIATE de tous les secrets exposés, puis git filter-repo pour les retirer de l’historique.

5. Pas de npm audit / pip audit en CI

Cause : on installe les dépendances et on n’y revient jamais. Une CVE critique sur lodash ou requests reste exploitable des mois.

Solution : dans le pipeline CI : npm audit --audit-level=high (Node), pip-audit (Python), composer audit (PHP). Échec build sur CVE haute. Et activez Dependabot sur GitHub pour les PR automatiques.

Checklist sécurité pour chaque projet

  1. Requêtes SQL paramétrées (pas de concaténation)
  2. Validation et échappement de toutes les entrées utilisateur
  3. Mots de passe hashés avec bcrypt/Argon2
  4. HTTPS activé partout
  5. Secrets dans des variables d’environnement
  6. Headers de sécurité configurés (CSP, X-Frame-Options)
  7. Dépendances à jour (npm audit, pip audit)
  8. Logs de sécurité activés
  9. Tests de sécurité automatisés (SAST/DAST)

Pour creuser ce sujet

Un hébergeur abordable pour vos projets

Hostinger combine prix raisonnable et stabilité. Lien partenaire — pas de surcoût pour vous.

Choisir une offre →

Lien d affiliation. Si vous achetez via ce lien, le blog reçoit une petite commission sans surcoût pour vous.

Adopter le bon état d’esprit avant d’écrire du code

La sécurité n’est pas une couche que l’on ajoute à la fin, c’est une discipline qui imprègne chaque commit. Pour un développeur basé à Dakar, Cotonou ou Yaoundé, la réalité est crue : votre application traite parfois des numéros Orange Money ou Mixx by Yas, parfois des données d’identité, et un défaut de validation côté serveur expose immédiatement l’utilisateur final. Avant tout, intégrez la modélisation de menaces (threat modeling) dans vos sprints : qui attaque, pourquoi, par où. Cinq minutes de réflexion économisent des semaines d’incident.

Cette doctrine se traduit en pratique : revue de code obligatoire pour tout merge sur main, branche de production protégée, dépendances pinées, secrets sortis du repo. Ces règles paraissent évidentes, mais l’audit de la majorité des projets web ouest-africains montre l’inverse : clés API committées, mots de passe en clair dans des fichiers de configuration, dépendances non mises à jour depuis 18 mois.

Étape 1 — Sortir tous les secrets du code source

Aucune clé d’API, aucun mot de passe de base de données, aucun jeton OAuth ne doit apparaître dans Git, même dans une branche privée. L’historique Git est immuable : un secret poussé une seule fois reste accessible à vie, même après suppression du fichier.

# A la racine du projet
echo ".env" >> .gitignore
echo ".env.local" >> .gitignore
git rm --cached .env 2>/dev/null
git commit -m "chore: stop tracking .env"

Vérifiez ensuite avec git log --all -- .env qu’aucune trace résiduelle ne subsiste. Si une fuite a déjà eu lieu, considérez le secret comme compromis : changez-le immédiatement côté fournisseur. La rotation est la seule réponse fiable.

Étape 2 — Valider toutes les entrées utilisateur côté serveur

La règle d’or : ne jamais faire confiance au client. Un attaquant peut désactiver votre validation JavaScript en deux clics dans DevTools, modifier une requête avec curl ou Postman, ou injecter directement via une API publique. Toute donnée qui rentre dans votre serveur doit être validée selon un schéma strict.

// Avec Zod en TypeScript
import { z } from "zod";
const Schema = z.object({
  email: z.string().email().max(254),
  age: z.number().int().min(13).max(120),
});
const data = Schema.parse(req.body); // jette si invalide

L’output attendu : aucune route ne traite directement req.body brut. En cas d’entrée malformée, l’API renvoie un 400 explicite. Cette discipline bloque 80 % des injections (SQL, NoSQL, command, XSS stocké) à la racine.

Étape 3 — Utiliser des requêtes paramétrées contre l’injection SQL

L’injection SQL reste numéro 1 du Top 10 OWASP malgré 25 ans d’avertissements. La cause : la concaténation de chaînes pour construire des requêtes. La solution est triviale et gratuite : utiliser les requêtes préparées de votre driver.

// MAUVAIS
db.query("SELECT * FROM users WHERE email='" + email + "'");

// BON (Postgres avec node-postgres)
db.query("SELECT * FROM users WHERE email = $1", [email]);

Les ORM modernes (Prisma, Drizzle, TypeORM, SQLAlchemy) appliquent automatiquement cette règle. Si vous écrivez encore du SQL brut, faites-le toujours avec des paramètres positionnels. Aucune exception, même pour un script interne « rapide ».

Étape 4 — Hacher les mots de passe avec un algorithme adaptatif

Stocker un mot de passe en clair ou en MD5 vous expose à la mise hors service de votre service en cas de fuite. Utilisez bcrypt, scrypt ou argon2 — trois algorithmes lents conçus pour résister aux attaques par GPU. Argon2id est aujourd’hui recommandé par l’OWASP.

import argon2 from "argon2";
const hash = await argon2.hash(password, { type: argon2.argon2id });
const ok = await argon2.verify(hash, password);

Mesurez le temps de hachage cible : entre 200 et 500 ms en production. Plus rapide, votre coût d’attaque par brute force devient trivial sur une carte graphique. Plus lent, votre serveur ploie sous une vague d’authentifications légitimes.

Étape 5 — Activer HTTPS strict et HSTS

HTTPS n’est plus optionnel, même pour un site vitrine. Let’s Encrypt fournit des certificats gratuits valables 90 jours, renouvelés automatiquement par Certbot ou par votre hébergeur. Ajoutez ensuite l’en-tête HSTS pour forcer le navigateur à refuser tout downgrade en HTTP.

# Dans Nginx
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;

Vérifiez votre configuration sur securityheaders.com et ssllabs.com — visez un grade A minimum. Un certificat correctement configuré bloque les attaques man-in-the-middle sur les Wi-Fi publics fréquents dans les coworkings de Plateau ou de Marcory.

Étape 6 — Mettre en place une politique CSP stricte

Content Security Policy reste votre meilleure défense contre les XSS reflétés et stockés. L’idée : déclarer explicitement les sources de scripts, styles et images autorisées. Tout le reste est bloqué par le navigateur, même si un attaquant injecte une balise.

Content-Security-Policy:
  default-src 'self';
  script-src 'self' https://cdn.example.com;
  style-src 'self' 'unsafe-inline';
  img-src 'self' data: https:;
  frame-ancestors 'none';

Démarrez en mode Content-Security-Policy-Report-Only pendant une semaine pour collecter les violations sans casser la production. Une fois les exceptions traitées, basculez en mode bloquant. L’output attendu : zéro script externe non autorisé n’a la possibilité de s’exécuter.

Étape 7 — Gérer les dépendances avec un audit hebdomadaire

La majorité des failles modernes proviennent de la chaîne d’approvisionnement : un paquet npm ou pip vulnérable inclus en transitif suffit. Automatisez le scan dans votre pipeline CI/CD et ne déployez jamais avec des vulnérabilités critiques connues.

# Node.js
npm audit --omit=dev
npm audit fix

# Python
pip install pip-audit
pip-audit -r requirements.txt

Activez Dependabot ou Renovate sur GitHub pour recevoir une PR automatique à chaque mise à jour de sécurité. Pour un projet en production, fixez les versions exactes (lockfile committé) et passez en revue chaque montée mineure avant merge.

Étape 8 — Logger sans exposer de données sensibles

Un bon logging accélère l’investigation post-incident. Un mauvais logging crée la fuite suivante. Ne loguez jamais : mot de passe, token JWT complet, numéro de carte, OTP, jeton de session, en-tête Authorization brut. Utilisez un middleware qui filtre ces champs avant écriture.

// Avec pino (Node.js)
import pino from "pino";
const log = pino({
  redact: { paths: ["password","token","authorization","otp"], censor: "[REDACTED]" }
});
log.info({ email, password: "secret" }); // password remplace par [REDACTED]

Centralisez ensuite les logs dans Loki, Elasticsearch ou un service managé, avec une rétention de 90 jours minimum. En cas d’incident — tentative d’intrusion, abus d’API, fraude Mixx by Yas — vous reconstituez la chronologie en quelques minutes, ce qui change tout face à un client ou un régulateur.

Service ITSkillsCenter

Application mobile Android et iOS

Création d'application mobile Android et iOS. À partir de 350 000 FCFA.

Démarrer mon projet
Publicité