Envoyer des données d'un endroit à un autre? Pour votre propre tranquillité d'esprit et la protection de vos utilisateurs, vous devez le sécuriser avec JWT.
Lorsque vous créez une application, il est essentiel de protéger les données sensibles contre tout accès non autorisé. De nombreuses applications Web, mobiles et cloud modernes utilisent les API REST comme principal moyen de communication. Par conséquent, il est crucial de concevoir et de développer des API backend avec la sécurité au premier plan.
Une approche efficace pour sécuriser une API REST implique les jetons Web JSON (JWT). Ces jetons offrent un mécanisme robuste d'authentification et d'autorisation des utilisateurs, aidant à protéger les ressources protégées contre l'accès par des acteurs malveillants.
Que sont les jetons Web JSON?
Jeton Web JSON (JWT) est une norme de sécurité largement utilisée. Il fournit une méthode concise et autonome de transmission sécurisée des données entre une application cliente et un système backend.
Une API REST peut utiliser des JWT pour identifier et authentifier en toute sécurité les utilisateurs lorsqu'ils effectuent des requêtes HTTP pour accéder à des ressources protégées.
Un jeton Web JSON se compose de trois parties distinctes: l'en-tête, la charge utile et la signature. Il encode chaque partie et les concatène à l'aide d'un point (".").
L'en-tête décrit l'algorithme cryptographique utilisé pour signer le jeton, tandis que la charge utile contient des données sur l'utilisateur et toute métadonnée supplémentaire.
Enfin, la signature, calculée à l'aide de l'en-tête, de la charge utile et de la clé secrète, garantit l'intégrité et l'authenticité du jeton.
Avec les bases des JWT à l'écart, construisons une API REST Node.js et implémentons les JWT.
Configurer une application Express.js et une base de données MongoDB
Vous découvrirez ici comment construire une authentification simple API REST qui gère à la fois les fonctionnalités d'enregistrement et de connexion. Une fois que le processus de connexion authentifie un utilisateur, celui-ci doit pouvoir envoyer des requêtes HTTP à une route d'API protégée.
Vous pouvez trouver le code du projet dans ce Référentiel GitHub.
Pour commencer, créer un serveur Web Express, et installez ces packages :
npm installer cors dotenv bycrpt mongoose analyseur de cookies crypto jsonwebtoken mongodb
Suivant, créer une base de données MongoDB ou configurer un cluster MongoDB sur le cloud. Ensuite, copiez la chaîne de connexion à la base de données, créez un .env fichier dans le répertoire racine et collez-y la chaîne de connexion :
CONNECTION_STRING="chaîne de connexion"
Configurer la connexion à la base de données
Créer un nouveau utils/db.js fichier dans le répertoire racine de votre dossier de projet. Dans ce fichier, ajoutez le code suivant pour établir la connexion à la base de données à l'aide de Mongoose.
constante mangouste = exiger('mangouste');
constante connectDB = asynchrone () => {
essayer {
attendre mongoose.connect (process.env. CHAÎNE DE CONNEXION);
console.enregistrer("Connecté à MongoDB !");
} attraper (erreur) {
console.erreur("Erreur de connexion à MongoDB :", erreur);
}
};
module.exports = connectDB;
Définir le modèle de données
Définissez un schéma de données utilisateur simple à l'aide de Mongoose. Dans le répertoire racine, créez un nouveau modèle/utilisateur.model.js fichier et ajoutez le code suivant.
constante mangouste = exiger('mangouste');
constante userSchema = nouveau mangouste. Schéma({
nom d'utilisateur: Chaîne,
mot de passe: {
taper: Chaîne,
requis: vrai,
unique: vrai,
},
});
constante Utilisateur = mangouste.model("Utilisateur", userSchema);
module.exports = Utilisateur ;
Définir les contrôleurs pour les routes d'API
Les fonctions du contrôleur géreront l'enregistrement et la connexion; ils constituent une partie importante de cet exemple de programme. Dans le répertoire racine, créez un controllers/userControllers.js fichier et ajoutez le code suivant :
- Définissez le contrôleur d'enregistrement des utilisateurs.
Cet extrait de code hache le mot de passe fourni à l'aide de bcrypt, puis crée un nouvel enregistrement d'utilisateur dans la base de données, stockant le nom d'utilisateur et le mot de passe haché. Si l'enregistrement réussit, il envoie une réponse avec un message de réussite.constante Utilisateur = exiger('../modèles/utilisateur.modèle');
constante bcrypt = exiger('bcrypt');
constante { générer un jeton } = exiger('../middleware/auth');exports.registerUser = asynchrone (req, res) => {
constante { nom d'utilisateur, mot de passe } = req.body ;essayer {
constante hachage = attendre bcrypt.hash (mot de passe, 10);
attendre User.create({ nom d'utilisateur, mot de passe: hachage });
res.statut(201).envoyer({ message: 'Utilisateur enregistré avec succès' });
} attraper (erreur) {
console.log (erreur);
res.statut(500).envoyer({ message: 'Une erreur s'est produite!! ' });
}
}; - Définissez un contrôleur de connexion pour gérer le processus de connexion de l'utilisateur :
Lorsqu'un utilisateur envoie une demande au /login route, ils doivent transmettre leurs identifiants d'authentification dans le corps de la requête. Le code vérifie ensuite ces informations d'identification et génère un jeton Web JSON. Le jeton est stocké en toute sécurité dans un cookie avec le httpUniquement drapeau défini sur vrai. Cela empêche JavaScript côté client d'accéder au jeton, ce qui protège contre les attaques potentielles de script intersite (XSS).exports.loginUser = asynchrone (req, res) => {
constante { nom d'utilisateur, mot de passe } = req.body ;essayer {
constante utilisateur = attendre User.findOne({ nom d'utilisateur });
si (!utilisateur) {
retour res.statut(404).envoyer({ message: 'Utilisateur non trouvé' });
}constante mot de passeMatch = attendre bcrypt.compare (mot de passe, utilisateur.motdepasse);
si (!passwordMatch) {
retour res.statut(401).envoyer({ message: 'Authentification invalide' });
}constante charge utile = { ID de l'utilisateur: ID de l'utilisateur };
constante jeton = generateToken (charge utile);
res.cookie('jeton', jeton, { httpUniquement: vrai });
res.statut(200).json({ message: 'Connexion réussie'});
} attraper (erreur) {
console.log (erreur);
res.statut(500).envoyer({ message: 'Une erreur s'est produite lors de la connexion' });
}
}; - Enfin, définissez une route protégée :
En stockant le JWT dans un cookie, les requêtes API ultérieures de l'utilisateur authentifié incluront automatiquement le jeton, permettant au serveur de valider et d'autoriser les requêtes.exports.getUsers = asynchrone (req, res) => {
essayer {
constante utilisateurs = attendre Utilisateur.find({});
res.json (utilisateurs);
} attraper (erreur) {
console.log (erreur);
res.statut(500).envoyer({ message: 'Une erreur s'est produite !!' });
}
};
Créer un middleware d'authentification
Maintenant que vous avez défini un contrôleur de connexion qui génère un jeton JWT lors d'une authentification réussie, définissez les fonctions d'authentification middleware qui généreront et vérifieront le jeton JWT.
Dans le répertoire racine, créez un nouveau dossier, middleware. Dans ce dossier, ajoutez deux fichiers: auth.js et config.js.
Ajoutez ce code à config.js:
constante crypto = exiger('crypto');
module.exports = {
clé secrète: crypto.randomBytes(32).toString('hexagone')
};
Ce code génère une nouvelle clé secrète aléatoire à chaque exécution. Vous pouvez ensuite utiliser cette clé secrète pour signer et vérifier l'authenticité des JWT. Une fois qu'un utilisateur est authentifié avec succès, générez et signez un JWT avec la clé secrète. Le serveur utilisera ensuite la clé pour vérifier que le JWT est valide.
Ajoutez le code suivant dans auth.js qui définit les fonctions middleware qui génèrent et vérifient les JWT.
constante jwt = exiger('jsonwebtoken');
constante {clésecrète} = exiger('./config');constante générer un jeton = (charge utile) => {
constante jeton = jwt.sign (charge utile, clé secrète, { expire dans: '1h' });
retour jeton ;
};constante vérifierJeton = (req, res, suivant) => {
constante jeton = req.cookies.token ;si (!jeton) {
retour res.statut(401).json({ message: 'Aucun jeton fourni' });
}jwt.verify (token, secretKey, (err, décodé) => {
si (erre) {
retour res.statut(401).json({ message: 'Jeton invalide' });
}req.userId = décodé.userId ;
suivant();
});
};
module.exports = { générerToken, vérifierToken } ;
Le générer un jeton La fonction génère un JWT en signant une charge utile à l'aide d'une clé secrète et en définissant un délai d'expiration pendant que le vérifier le jeton La fonction sert de middleware pour vérifier l'authenticité et la validité d'un jeton fourni.
Définir les routes d'API
Créer un nouveau routes/userRoutes.js fichier dans le répertoire racine et ajoutez le code suivant.
constante exprimer = exiger('exprimer');
constante routeur = express. Routeur();
constante userControllers = exiger('../controllers/userControllers');
constante {verifyToken} = exiger('../middleware/auth');
routeur.post('/api/s'inscrire', userControllers.registerUser);
routeur.post('/api/connexion', userControllers.loginUser);
routeur.get('/api/utilisateurs', verifyToken, userControllers.getUsers);
module.exports = routeur ;
Mettez à jour votre point d'entrée de serveur
Mettez à jour votre serveur.js fichier avec le code suivant.
constante exprimer = exiger('exprimer');
constante cors = exiger('cors');
constante app = express();
constante port = 5000;
exiger('dotenv').config();
constante connectDB = exiger('./utils/db');
constante cookieParser = exiger('analyseur de cookies');connectDB();
app.use (express.json());
app.use (express.urlencodé({ étendu: vrai }));
app.use (cors());
app.use (cookieParser());
constante userRoutes = exiger('./routes/userRoutes');
app.use('/', userRoutes);
app.listen (port, () => {
console.enregistrer(`Le serveur écoute à http://localhost:${port}`);
});
Pour tester l'API REST, lancez le serveur de développement et envoyez des requêtes d'API aux points de terminaison définis :
nœud serveur.js
Sécurisation des API REST Node.js
La sécurisation des API REST Node.js va au-delà de la simple utilisation des JWT, bien qu'ils jouent un rôle crucial dans l'authentification et autorisation, il est essentiel d'adopter une approche holistique de la sécurité pour protéger votre backend systèmes. Parallèlement aux JWT, vous devriez également envisager de mettre en œuvre HTTPS pour chiffrer la communication, la validation et la désinfection des entrées, et bien d'autres.
En combinant plusieurs mesures de sécurité, vous pouvez établir un cadre de sécurité robuste pour votre API REST Node.js et minimisez le risque d'accès non autorisé, de violation de données et d'autres mesures de sécurité des menaces.