Dans le paysage numérique actuel, la sécurisation de votre application Node.js est primordiale. Des leaders mondiaux comme Netflix et Uber aux startups qui créent la prochaine grande nouveauté, Node.js alimente certaines des applications les plus exigeantes et les plus performantes. Cependant, les vulnérabilités de votre application peuvent entraîner un accès non autorisé, des violations de données et une perte de confiance des utilisateurs.
Ce guide combine des pratiques de sécurité pratiques avec les concepts clés du OWASP Web Security Testing Guide (WSTG) pour vous aider à renforcer votre application Node.js. Que vous gériez des opérations en temps réel ou que vous évoluiez vers des millions d'utilisateurs, cette ressource complète garantira que votre application reste sécurisée, fiable et résiliente.
Collecte d'informations est souvent la première étape franchie par un attaquant pour en savoir plus sur votre application. Plus ils peuvent collecter d’informations, plus il leur devient facile d’identifier et d’exploiter les vulnérabilités.
Par défaut, Express.js inclut des paramètres qui peuvent révéler par inadvertance des informations sur votre serveur. Un exemple courant est l'en-tête HTTP X-Powered-By, qui indique que votre application utilise Express.
Exemple de code vulnérable :
const express = require('express'); const app = express(); // Your routes here app.listen(3000, () => { console.log('Server is running on port 3000'); });
Dans cette configuration, chaque réponse HTTP inclut l'en-tête X-Powered-By: Express.
Problème :
Atténuation :
Désactivez cet en-tête pour rendre plus difficile aux attaquants l'empreinte digitale de votre serveur.
Code amélioré :
const express = require('express'); const app = express(); // Disable the X-Powered-By header app.disable('x-powered-by'); // Your routes here app.listen(3000, () => { console.log('Server is running on port 3000'); });
Atténuation améliorée avec un casque :
Une meilleure approche consiste à utiliser le middleware du casque, qui définit divers en-têtes HTTP pour améliorer la sécurité de votre application.
const express = require('express'); const helmet = require('helmet'); const app = express(); // Use Helmet to secure headers app.use(helmet()); // Your routes here app.listen(3000, () => { console.log('Server is running on port 3000'); });
Pourquoi utiliser un casque ?
Gestion de la configuration et du déploiement sont des aspects critiques de la sécurité des applications. Les mauvaises configurations peuvent servir de portes ouvertes aux attaquants.
L'exécution de votre application en mode développement sur un serveur de production peut exposer des messages d'erreur détaillés et des traces de pile.
Exemple de code vulnérable :
const express = require('express'); const app = express(); // Your routes here app.listen(3000, () => { console.log('Server is running on port 3000'); });
Dans cette configuration, des messages d'erreur détaillés sont envoyés au client.
Problème :
Atténuation :
Définissez NODE_ENV sur « production » et utilisez des messages d'erreur génériques en production.
Code amélioré :
const express = require('express'); const app = express(); // Disable the X-Powered-By header app.disable('x-powered-by'); // Your routes here app.listen(3000, () => { console.log('Server is running on port 3000'); });
Bonnes pratiques :
L'utilisation d'informations d'identification par défaut ou faibles, telles qu'une simple clé secrète pour signer les jetons Web JSON (JWT), est une erreur de sécurité courante.
Exemple de code vulnérable :
const express = require('express'); const helmet = require('helmet'); const app = express(); // Use Helmet to secure headers app.use(helmet()); // Your routes here app.listen(3000, () => { console.log('Server is running on port 3000'); });
Problème :
Atténuation :
Utilisez une clé secrète solide et sécurisée et stockez-la en toute sécurité.
Code amélioré :
// app.js const express = require('express'); const app = express(); // Error handling middleware app.use((err, req, res, next) => { res.status(500).send(err.stack); // Sends stack trace to the client }); // Your routes here app.listen(3000);
Bonnes pratiques :
La gestion des identités est cruciale pour protéger les comptes d'utilisateurs et empêcher tout accès non autorisé.
Autoriser les noms d'utilisateur faibles et fournir des messages d'erreur spécifiques peut conduire à des attaques par énumération de comptes.
Exemple de code vulnérable :
const express = require('express'); const app = express(); // Your routes here app.listen(3000, () => { console.log('Server is running on port 3000'); });
Problème :
Atténuation :
Implémentez la validation du nom d'utilisateur et utilisez des messages d'erreur génériques.
Code amélioré :
const express = require('express'); const app = express(); // Disable the X-Powered-By header app.disable('x-powered-by'); // Your routes here app.listen(3000, () => { console.log('Server is running on port 3000'); });
Explication :
Authentification sont essentiels pour vérifier l'identité des utilisateurs et empêcher tout accès non autorisé.
Le manque de protection permet aux attaquants de deviner des mots de passe ou des codes 2FA grâce à des tentatives répétées.
Exemple de code vulnérable :
const express = require('express'); const helmet = require('helmet'); const app = express(); // Use Helmet to secure headers app.use(helmet()); // Your routes here app.listen(3000, () => { console.log('Server is running on port 3000'); });
Problème :
Atténuation :
Mettre en œuvre une limitation du débit et améliorer la sécurité 2FA.
Code amélioré :
// app.js const express = require('express'); const app = express(); // Error handling middleware app.use((err, req, res, next) => { res.status(500).send(err.stack); // Sends stack trace to the client }); // Your routes here app.listen(3000);
Mesures supplémentaires :
Explication :
Autorisation garantit que les utilisateurs accèdent uniquement aux ressources qu'ils sont autorisés à utiliser, empêchant ainsi les actions non autorisées.
Les utilisateurs peuvent accéder à des ressources non autorisées en manipulant les identifiants dans les requêtes.
Exemple de code vulnérable :
// app.js const express = require('express'); const app = express(); // Your routes here // Error handling middleware if (app.get('env') === 'production') { // Production error handler app.use((err, req, res, next) => { // Log the error internally console.error(err); res.status(500).send('An unexpected error occurred.'); }); } else { // Development error handler (with stack trace) app.use((err, req, res, next) => { res.status(500).send(`<pre class="brush:php;toolbar:false">${err.stack}`); }); } app.listen(3000);
Problème :
Atténuation :
Validez la propriété de la ressource avant de fournir l'accès.
Code amélioré :
const express = require('express'); const app = express(); // Your routes here app.listen(3000, () => { console.log('Server is running on port 3000'); });
Explication :
La gestion des sessions est essentielle pour maintenir l'état des utilisateurs et garantir des interactions sécurisées.
Les jetons qui n'expirent jamais présentent un risque de sécurité s'ils sont compromis.
Exemple de code vulnérable :
const express = require('express'); const app = express(); // Disable the X-Powered-By header app.disable('x-powered-by'); // Your routes here app.listen(3000, () => { console.log('Server is running on port 3000'); });
Problème :
Atténuation :
Définissez un délai d'expiration sur les jetons.
Code amélioré :
const express = require('express'); const helmet = require('helmet'); const app = express(); // Use Helmet to secure headers app.use(helmet()); // Your routes here app.listen(3000, () => { console.log('Server is running on port 3000'); });
Explication :
Le stockage des jetons dans localStorage les expose aux attaques de script intersite (XSS).
Exemple de code vulnérable :
// app.js const express = require('express'); const app = express(); // Error handling middleware app.use((err, req, res, next) => { res.status(500).send(err.stack); // Sends stack trace to the client }); // Your routes here app.listen(3000);
Problème :
Atténuation :
Utilisez des cookies HTTP uniquement pour stocker les jetons en toute sécurité.
Code amélioré :
// app.js const express = require('express'); const app = express(); // Your routes here // Error handling middleware if (app.get('env') === 'production') { // Production error handler app.use((err, req, res, next) => { // Log the error internally console.error(err); res.status(500).send('An unexpected error occurred.'); }); } else { // Development error handler (with stack trace) app.use((err, req, res, next) => { res.status(500).send(`<pre class="brush:php;toolbar:false">${err.stack}`); }); } app.listen(3000);
Explication :
La validation des entrées garantit que les données fournies par l'utilisateur sont sûres et attendues, empêchant ainsi les attaques par injection.
Accepter et traiter les entrées des utilisateurs sans validation peut entraîner des vulnérabilités.
Exemple de code vulnérable :
const express = require('express'); const jwt = require('jsonwebtoken'); const app = express(); // Weak secret key const SECRET_KEY = 'secret'; app.post('/login', (req, res) => { // Authenticate user (authentication logic not shown) const userId = req.body.userId; // Sign the JWT with a weak secret const token = jwt.sign({ userId }, SECRET_KEY); res.json({ token }); }); app.get('/protected', (req, res) => { const token = req.headers['authorization']; try { // Verify the token using the weak secret const decoded = jwt.verify(token, SECRET_KEY); res.send('Access granted to protected data'); } catch (err) { res.status(401).send('Unauthorized'); } }); app.listen(3000, () => { console.log('Server started on port 3000'); });
Problème :
Atténuation :
Validez et désinfectez toutes les entrées utilisateur.
Code amélioré :
const express = require('express'); const app = express(); // Your routes here app.listen(3000, () => { console.log('Server is running on port 3000'); });
Explication :
Une gestion appropriée des erreurs évite de divulguer des informations sensibles et améliore l'expérience utilisateur.
Des messages d'erreur détaillés peuvent révéler les composants internes du système aux attaquants.
Exemple de code vulnérable :
const express = require('express'); const app = express(); // Disable the X-Powered-By header app.disable('x-powered-by'); // Your routes here app.listen(3000, () => { console.log('Server is running on port 3000'); });
Problème :
Atténuation :
Utilisez des messages d'erreur génériques et enregistrez les erreurs détaillées en interne.
Code amélioré :
const express = require('express'); const helmet = require('helmet'); const app = express(); // Use Helmet to secure headers app.use(helmet()); // Your routes here app.listen(3000, () => { console.log('Server is running on port 3000'); });
Explication :
Cryptographie protège les données sensibles ; l'utilisation de pratiques cryptographiques faibles compromet la sécurité.
Le hachage de mots de passe avec des algorithmes obsolètes n'est pas sécurisé.
Exemple de code vulnérable :
// app.js const express = require('express'); const app = express(); // Error handling middleware app.use((err, req, res, next) => { res.status(500).send(err.stack); // Sends stack trace to the client }); // Your routes here app.listen(3000);
Problème :
Atténuation :
Utilisez un algorithme de hachage puissant conçu pour les mots de passe.
Code amélioré :
// app.js const express = require('express'); const app = express(); // Your routes here // Error handling middleware if (app.get('env') === 'production') { // Production error handler app.use((err, req, res, next) => { // Log the error internally console.error(err); res.status(500).send('An unexpected error occurred.'); }); } else { // Development error handler (with stack trace) app.use((err, req, res, next) => { res.status(500).send(`<pre class="brush:php;toolbar:false">${err.stack}`); }); } app.listen(3000);
Explication :
Le stockage des secrets directement dans le code augmente le risque d'exposition.
Exemple de code vulnérable :
const express = require('express'); const jwt = require('jsonwebtoken'); const app = express(); // Weak secret key const SECRET_KEY = 'secret'; app.post('/login', (req, res) => { // Authenticate user (authentication logic not shown) const userId = req.body.userId; // Sign the JWT with a weak secret const token = jwt.sign({ userId }, SECRET_KEY); res.json({ token }); }); app.get('/protected', (req, res) => { const token = req.headers['authorization']; try { // Verify the token using the weak secret const decoded = jwt.verify(token, SECRET_KEY); res.send('Access granted to protected data'); } catch (err) { res.status(401).send('Unauthorized'); } }); app.listen(3000, () => { console.log('Server started on port 3000'); });
Problème :
Atténuation :
Stockez les secrets dans des variables d'environnement ou des fichiers de configuration sécurisés.
Code amélioré :
const express = require('express'); const app = express(); // Your routes here app.listen(3000, () => { console.log('Server is running on port 3000'); });
Explication :
Logique métier se produisent lorsque les flux d'applications peuvent être manipulés de manière involontaire.
Les opérations de données sans restriction peuvent entraîner des problèmes de performances ou des fuites de données.
Exemple de code vulnérable :
const express = require('express'); const app = express(); // Disable the X-Powered-By header app.disable('x-powered-by'); // Your routes here app.listen(3000, () => { console.log('Server is running on port 3000'); });
Problème :
Atténuation :
Mettre en œuvre des contrôles de pagination et d'accès.
Code amélioré :
const express = require('express'); const helmet = require('helmet'); const app = express(); // Use Helmet to secure headers app.use(helmet()); // Your routes here app.listen(3000, () => { console.log('Server is running on port 3000'); });
Explication :
La protection contre les vulnérabilités côté client est essentielle pour protéger les utilisateurs contre les attaques telles que le Cross-Site Scripting (XSS).
Une mauvaise gestion des entrées utilisateur dans les scripts côté client peut conduire à des attaques XSS.
Exemple de code vulnérable :
// app.js const express = require('express'); const app = express(); // Error handling middleware app.use((err, req, res, next) => { res.status(500).send(err.stack); // Sends stack trace to the client }); // Your routes here app.listen(3000);
Problème :
Atténuation :
Utilisez la bibliothèque XSS pour nettoyer les entrées de l'utilisateur avant le rendu.
Code amélioré :
// app.js const express = require('express'); const app = express(); // Your routes here // Error handling middleware if (app.get('env') === 'production') { // Production error handler app.use((err, req, res, next) => { // Log the error internally console.error(err); res.status(500).send('An unexpected error occurred.'); }); } else { // Development error handler (with stack trace) app.use((err, req, res, next) => { res.status(500).send(`<pre class="brush:php;toolbar:false">${err.stack}`); }); } app.listen(3000);
Explication :
Bonnes pratiques :
const express = require('express'); const app = express(); // Your routes here app.listen(3000, () => { console.log('Server is running on port 3000'); });
La sécurisation des points de terminaison de l'API est cruciale pour éviter les fuites de données et les accès non autorisés.
Quitter l'introspection GraphQL activée en production révèle votre schéma API.
Exemple de code vulnérable :
const express = require('express'); const app = express(); // Disable the X-Powered-By header app.disable('x-powered-by'); // Your routes here app.listen(3000, () => { console.log('Server is running on port 3000'); });
Problème :
Atténuation :
Désactivez l'introspection dans les environnements de production.
Code amélioré :
const express = require('express'); const helmet = require('helmet'); const app = express(); // Use Helmet to secure headers app.use(helmet()); // Your routes here app.listen(3000, () => { console.log('Server is running on port 3000'); });
Explication :
Les requêtes profondément imbriquées ou complexes peuvent épuiser les ressources du serveur.
Exemple de code vulnérable :
// app.js const express = require('express'); const app = express(); // Error handling middleware app.use((err, req, res, next) => { res.status(500).send(err.stack); // Sends stack trace to the client }); // Your routes here app.listen(3000);
Problème :
Atténuation :
Limiter la profondeur et la complexité des requêtes.
Code amélioré :
// app.js const express = require('express'); const app = express(); // Your routes here // Error handling middleware if (app.get('env') === 'production') { // Production error handler app.use((err, req, res, next) => { // Log the error internally console.error(err); res.status(500).send('An unexpected error occurred.'); }); } else { // Development error handler (with stack trace) app.use((err, req, res, next) => { res.status(500).send(`<pre class="brush:php;toolbar:false">${err.stack}`); }); } app.listen(3000);
Explication :
Sécuriser votre application Node.js implique une approche à plusieurs niveaux :
En intégrant ces pratiques, vous améliorez la sécurité de votre application, protégez les données des utilisateurs et maintenez la confiance.
Remarque : ce guide fournit des recommandations générales. Pour des problèmes de sécurité spécifiques, consultez un professionnel.
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!