Sécurité des applications JavaScript : top 10 des vulnérabilités
JavaScript, en particulier dans l'environnement Node.js, est devenu le fondement du développement web moderne. Cependant, sa popularité rend les applications une cible attrayante pour les attaques. Ignorer les questions de sécurité peut entraîner des fuites de données, des pertes financières et des dommages à la réputation. Dans cet article, nous analyserons le top 10 des vulnérabilités les plus critiques des applications JavaScript (Node.js), basé sur le standard OWASP Top 10, et montrerons comment les prévenir à l'aide d'exemples de code.
1. Injections (Injection)
Les injections restent l'une des menaces les plus dangereuses. Dans le contexte de Node.js, on rencontre le plus souvent les injections SQL et les injections NoSQL (par exemple, dans MongoDB).
Problème
La concaténation directe de l'entrée utilisateur dans les requêtes à la base de données permet à un attaquant d'exécuter du code arbitraire.
Exemple de code vulnérable
const user = req.body.username;const query = `SELECT * FROM users WHERE username = '${user}'`;db.query(query, callback);Solution
Utilisez des requêtes paramétrées ou un ORM/ODM. Pour MongoDB, utilisez mongo-sanitize.
const query = 'SELECT * FROM users WHERE username = $1';db.query(query, [user], callback);2. Violation de l'authentification et de la gestion des sessions
Une authentification faible est une voie directe vers la compromission des comptes.
Problème
Utilisation de jetons prévisibles (par exemple, JWT avec l'algorithme none), stockage des mots de passe en clair ou absence de limitation du nombre de tentatives de connexion.
Exemple de vulnérabilité
// JWT sans vérification de l'algorithmeconst token = jwt.sign({ user: 'admin' }, 'secret', { algorithm: 'none' });Solution
- Vérifiez toujours l'algorithme JWT :
jwt.verify(token, secret, { algorithms: ['HS256'] }). - Stockez les mots de passe via
bcryptouargon2. - Mettez en place une limite de tentatives de connexion (
express-rate-limit).
const bcrypt = require('bcrypt');const saltRounds = 10;const hash = await bcrypt.hash(password, saltRounds);3. XSS (Cross-Site Scripting)
Le XSS permet d'injecter un script malveillant dans une page web, qui s'exécute ensuite dans le navigateur de la victime.
Problème
Affichage de contenu utilisateur sans échappement, en particulier lors de l'utilisation du Server-Side Rendering (SSR) dans Next.js ou Nuxt.js.
Code vulnérable (Express)
res.send(`<h1>Hello, ${req.query.name}</h1>`);Solution
- Échappez la sortie : utilisez les bibliothèques
escape-htmlou les moteurs de templates avec auto-échappement (EJS, Pug). - Définissez l'en-tête CSP (Content Security Policy) :
helmet.contentSecurityPolicy().
const helmet = require('helmet');app.use(helmet.contentSecurityPolicy({ directives: { defaultSrc: ["'self'"] }}));4. Références directes non sécurisées aux objets (IDOR)
La vulnérabilité survient lorsqu'un utilisateur peut accéder à des objets (fichiers, enregistrements de base de données) en connaissant ou en devinant leur identifiant.
Exemple
app.get('/api/user/:id', (req, res) => { // Aucune vérification que req.user.id === req.params.id const user = db.findUser(req.params.id); res.json(user);});Solution
Vérifiez toujours les droits d'accès au niveau du serveur.
if (req.user.id !== req.params.id) { return res.status(403).send('Forbidden');}5. Configuration de sécurité non sécurisée
Cela inclut l'utilisation d'identifiants par défaut, de modes de débogage en production, ainsi que des configurations CORS incorrectes.
Problème
// CORS ouvertapp.use(cors({ origin: '*' }));