Publie le 24 mars 2026 Par

Sécurité web pour développeurs : OWASP, injections, secrets, HTTPS — les bases

La sécurité n’est pas un module à ajouter à la fin — c’est une pratique à intégrer dès le début. En 2026, les développeurs juniors qui ne connaissent pas les vulnérabilités de base (SQL injection, XSS, secrets exposés) ont du mal à passer les entretiens techniques des équipes sérieuses. Ce guide couvre ce que tout développeur doit savoir, sans être expert en sécurité.

L’OWASP Top 10 — les vulnérabilités les plus courantes

L’OWASP (Open Web Application Security Project) publie le Top 10 des vulnérabilités web les plus répandues. En 2026, les plus pertinentes pour un développeur :

1. Injection (SQL, NoSQL, commandes)

// ❌ SQL injection — l'entrée utilisateur est directement dans la requête
const query = `SELECT * FROM users WHERE email = '${userInput}'`
// Si userInput = "'; DROP TABLE users; --" → désastre

// ✅ Requêtes paramétrées — toujours
const user = await db.query('SELECT * FROM users WHERE email = $1', [userInput])

// Avec Prisma — automatiquement protégé
const user = await prisma.user.findUnique({
  where: { email: userInput },
})

// ❌ Injection de commande shell
exec(`convert ${filename}`)  // filename = "img.jpg; rm -rf /"

// ✅ Valider et assainir les entrées
const safeFilename = path.basename(filename).replace(/[^a-z0-9.-]/gi, '')
execFile('convert', [safeFilename])

2. Cross-Site Scripting (XSS)

// ❌ Injecter du HTML non sanitisé dans le DOM
element.innerHTML = userInput  // si input = ""

// ✅ React échappe automatiquement — utilisez JSX
{userInput}
// sécurisé par défaut // ⚠️ dangerouslySetInnerHTML — uniquement avec un sanitizer import DOMPurify from 'dompurify'

3. Contrôle d’accès défaillant

// ❌ Vérifier l'identité mais pas les autorisations
app.get('/api/orders/:id', authenticate, async (req, res) => {
  const order = await Order.findById(req.params.id) // n'importe quel user peut voir n'importe quelle commande
  res.json(order)
})

// ✅ Vérifier que l'utilisateur a accès à cette ressource
app.get('/api/orders/:id', authenticate, async (req, res) => {
  const order = await Order.findOne({
    _id: req.params.id,
    userId: req.user.id,  // s'assurer que la commande appartient à cet utilisateur
  })
  if (!order) return res.status(404).json({ error: 'Not found' })
  res.json(order)
})

La gestion des secrets — la faute la plus commune

# ❌ Secrets dans le code source — commité sur GitHub
const API_KEY = 'sk-prod-abc123...'
DATABASE_URL = 'postgresql://user:password@prod-server'

# ✅ Variables d'environnement — jamais dans le code
const API_KEY = process.env.OPENAI_API_KEY

# .env (développement local — ne jamais commiter)
# .env.example (valeurs vides — commiter pour documenter)
OPENAI_API_KEY=
DATABASE_URL=
JWT_SECRET=

# .gitignore — toujours présent
.env
.env.local
.env.production

# Si vous avez commité un secret par erreur :
# 1. Révoquer immédiatement la clé compromise
# 2. Utiliser git-filter-repo pour supprimer de l'historique
# 3. Forcer le push (coordonner avec l'équipe)

HTTPS et headers de sécurité

// Next.js — headers de sécurité dans next.config.ts
const securityHeaders = [
  { key: 'X-Frame-Options', value: 'DENY' },
  { key: 'X-Content-Type-Options', value: 'nosniff' },
  { key: 'Referrer-Policy', value: 'strict-origin-when-cross-origin' },
  {
    key: 'Content-Security-Policy',
    value: "default-src 'self'; script-src 'self' 'unsafe-eval'; img-src 'self' data: https:"
  },
]

// Node.js/Express — avec helmet
import helmet from 'helmet'
app.use(helmet()) // applique une dizaine de headers de sécurité automatiquement

L’authentification — les pièges classiques

// ❌ Stocker des mots de passe en clair ou avec MD5
user.password = password  // catastrophique si la DB est compromise

// ✅ bcrypt ou argon2 — hachage avec salt
import bcrypt from 'bcrypt'
const hash = await bcrypt.hash(password, 12)  // 12 = cost factor
const isValid = await bcrypt.compare(plainPassword, hash)

// JWT — ne pas stocker de données sensibles dans le payload
// Le payload est encodé en base64, pas chiffré — lisible par n'importe qui
const token = jwt.sign(
  { userId: user.id, role: user.role },  // ✅ ok — pas de mot de passe ou données sensibles
  process.env.JWT_SECRET,
  { expiresIn: '7d' }
)

// Rate limiting — prévenir le brute force
import rateLimit from 'express-rate-limit'
const loginLimiter = rateLimit({
  windowMs: 15 * 60 * 1000, // 15 minutes
  max: 5,                    // 5 tentatives max
  message: 'Trop de tentatives, réessayez dans 15 minutes',
})

Offres développeur back-end et fullstack

Des postes pour développeurs qui codent de façon sécurisée — les équipes sérieuses testent les connaissances en sécurité dès l’entretien technique.

À lire aussi : Déploiement sur VPSMonitoringDevOps pour débutant

Categories : DevOps & Cloud