Sécurité des applications JavaScript : top 10 des vulnérabilités pour débutants
La sécurité des applications web est l'un des sujets les plus importants pour tout développeur. JavaScript (notamment côté serveur avec Node.js) est souvent une cible pour les attaquants en raison de sa popularité. Dans cet article, nous allons examiner les 10 vulnérabilités les plus courantes rencontrées par les développeurs débutants et montrer comment les éviter.
1. XSS (Cross-Site Scripting)
Le XSS est l'une des attaques les plus fréquentes, où un attaquant injecte un script malveillant dans une page web. Cela se produit lorsque les données de l'utilisateur sont insérées dans le HTML sans échappement.
Code dangereux (vulnérable) :
app.get('/search', (req, res) => { const query = req.query.q; res.send(`<h1>Résultats de recherche : ${query}</h1>`);});Code sécurisé (protection) :
const escapeHtml = require('escape-html');
app.get('/search', (req, res) => { const query = escapeHtml(req.query.q); res.send(`<h1>Résultats de recherche : ${query}</h1>`);});2. Injections SQL
Si vous utilisez des bases de données SQL (par exemple SQLite ou PostgreSQL), des requêtes non échappées peuvent entraîner une fuite de données.
Code dangereux :
const user = req.body.username;db.query(`SELECT * FROM users WHERE name = '${user}'`);Code sécurisé (utilisation de requêtes paramétrées) :
const user = req.body.username;db.query('SELECT * FROM users WHERE name = $1', [user]);3. Désérialisation non sécurisée
L'utilisation de JSON.parse() sur des données non vérifiées peut entraîner des attaques de type "prototype pollution".
Exemple de vulnérabilité :
const data = JSON.parse(req.body.jsonData);// Si data contient __proto__, cela peut modifier le prototype d'ObjectProtection : validez toujours les données avant l'analyse ou utilisez des bibliothèques comme fast-json-stable-stringify.
4. Absence de validation des entrées (Input Validation)
Ne faites jamais confiance aux données provenant de l'utilisateur. Vérifiez toujours le type, la longueur et le format des données.
// Mauvais : on accepte toutapp.post('/profile', (req, res) => { const { name, age } = req.body; // ...});
// Bon : on valideconst schema = { name: 'string', age: 'number' };if (typeof req.body.name !== 'string') throw new Error('Nom invalide');5. CSRF (Cross-Site Request Forgery)
Attaque où un attaquant force un utilisateur à effectuer une action non désirée sur un site où il est authentifié.
Protection : utilisez des jetons CSRF.
const csrf = require('csurf');app.use(csrf({ cookie: true }));
app.get('/form', (req, res) => { res.render('form', { csrfToken: req.csrfToken() });});6. Fuite d'informations via les erreurs
Ne montrez jamais de messages d'erreur détaillés aux utilisateurs — cela donne aux pirates des informations sur la structure de votre application.
Mauvais :
app.use((err, req, res, next) => { res.status(500).send(err.stack); // Fuite de la pile d'appels !});Bon :
app.use((err, req, res, next) => { console.error(err.stack); // On journalise pour nous res.status(500).send('Erreur interne du serveur');});7. Utilisation non sécurisée de eval() et Function()
Les fonctions eval() et new Function() exécutent une chaîne comme du code — c'est extrêmement dangereux si la chaîne contient des données utilisateur.
// Dangereux ! Ne faites jamais celaconst userInput = req.body.code;eval(userInput); // Un attaquant peut exécuter n'importe quel codeAlternative :