Leçon 15 / 20

Durcir les entrées et les secrets

25 min Node.js — production, files d’attente et sécurité Gratuit

Objectif : Valider les données reçues et protéger les identifiants utilisés par le service de commandes.

Une requête authentifiée peut encore contenir des données incorrectes ou inattendues. Si vous les transmettez directement à votre dépôt ou à un service métier, vous risquez des erreurs difficiles à diagnostiquer, des écritures incohérentes ou l’exposition d’informations internes.

Vous allez poser une frontière explicite entre les données reçues et celles que l’application accepte. Vous verrez également comment garder les secrets hors du code et réduire les détails retournés en cas d’erreur. Comme vu dans « Protéger les routes et les actions », cette validation complète l’authentification et l’autorisation : elle ne les remplace pas.

Valider avant d’appeler le service métier

Une validation d’entrée vérifie que les données ont la forme et les valeurs attendues par l’opération. Pour une création de commande, vous pouvez exiger un identifiant client non vide et une liste d’articles comprenant, pour chaque ligne, un identifiant de produit et une quantité entière positive. Vérifiez aussi le type des valeurs : la chaîne "3" n’est pas automatiquement une quantité numérique valide.

Acceptez uniquement les champs prévus par le contrat de la route : c’est une liste blanche. Les propriétés supplémentaires ne doivent pas être transmises au dépôt par inadvertance. Le code suivant est autonome et exécutable avec Node.js ; il valide un corps de requête sans dépendance externe et renvoie une erreur contrôlée plutôt qu’une exception détaillée.

Validation isolée des données d’une commandeJavaScript
function validerCommande(corps) {
  if (corps === null || typeof corps !== 'object' || Array.isArray(corps)) {
    return { valide: false, erreur: 'Corps de requête invalide.' };
  }

  const champsAutorises = new Set(['clientId', 'articles']);
  if (Object.keys(corps).some((champ) => !champsAutorises.has(champ))) {
    return { valide: false, erreur: 'Champ non autorisé.' };
  }

  if (typeof corps.clientId !== 'string' || corps.clientId.trim() === '') {
    return { valide: false, erreur: 'Identifiant client invalide.' };
  }

  if (!Array.isArray(corps.articles) || corps.articles.length === 0) {
    return { valide: false, erreur: 'La commande doit contenir des articles.' };
  }

  const articles = [];
  for (const article of corps.articles) {
    if (article === null || typeof article !== 'object' || Array.isArray(article)) {
      return { valide: false, erreur: 'Article invalide.' };
    }

    const champsArticle = new Set(['produitId', 'quantite']);
    if (Object.keys(article).some((champ) => !champsArticle.has(champ))) {
      return { valide: false, erreur: 'Champ d’article non autorisé.' };
    }
    if (typeof article.produitId !== 'string' || article.produitId.trim() === '') {
      return { valide: false, erreur: 'Identifiant de produit invalide.' };
    }
    if (!Number.isSafeInteger(article.quantite) || article.quantite < 1) {
      return { valide: false, erreur: 'Quantité invalide.' };
    }

    articles.push({ produitId: article.produitId.trim(), quantite: article.quantite });
  }

  return {
    valide: true,
    valeur: { clientId: corps.clientId.trim(), articles }
  };
}

const resultat = validerCommande({
  clientId: 'client-42',
  articles: [{ produitId: 'produit-7', quantite: 3 }]
});
console.log(resultat);
Aperçu du rendu
Chargement de l'aperçu…
Résultat attendu
{
  valide: true,
  valeur: {
    clientId: 'client-42',
    articles: [ { produitId: 'produit-7', quantite: 3 } ]
  }
}

Dans la route Express, appelez cette fonction avant le dépôt et ne transmettez au service métier que resultat.valeur lorsque resultat.valide vaut true. Vous pouvez répondre avec un statut 400 pour une entrée invalide, sans exposer une trace d’exécution. Gardez les règles métier plus profondes dans le service concerné : cette vérification porte sur la forme et les contraintes immédiates de la requête.

Protéger les secrets et les erreurs

Un secret applicatif est une valeur confidentielle utilisée pour accéder à une ressource ou vérifier une preuve, par exemple la clé de signature des jetons ou un mot de passe de base de données. Ne placez pas ces valeurs dans le dépôt de code, les fichiers de configuration partagés, les messages d’erreur ou les journaux. La configuration par environnement et son injection au démarrage ont été établies dans « Séparer la configuration par environnement » : fournissez les secrets à l’application par le mécanisme sécurisé prévu pour votre déploiement.

La rotation des secrets consiste à remplacer une valeur confidentielle selon une procédure maîtrisée, notamment lorsqu’elle doit être renouvelée ou a été exposée. Concevez les composants pour recevoir leur configuration par injection plutôt que de lire une valeur secrète à plusieurs endroits. Lors d’un remplacement, vous pouvez ainsi mettre à jour la source de configuration et organiser le changement sans ajouter le secret au code applicatif.

Réduire les informations d’erreur signifie distinguer ce qui est utile au client de ce qui sert au diagnostic interne. Le client reçoit un message stable et un statut adapté ; le journal interne peut conserver le contexte nécessaire, mais jamais un jeton, un mot de passe ou un corps contenant des données confidentielles. Pour les erreurs non prévues, renvoyez un message générique et associez l’événement à l’identifiant de corrélation, déjà introduit dans « Structurer les journaux de l’API ».

À retenir

  • Validez le type, la présence et les contraintes des champs avant tout appel au dépôt ou au service métier.
  • Construisez un objet à partir des seuls champs autorisés ; ne faites pas confiance aux propriétés supplémentaires reçues.
  • Injectez les secrets depuis la configuration sécurisée, ne les inscrivez ni dans le code ni dans les journaux, et prévoyez leur rotation.
  • Retournez des erreurs adaptées au client sans divulguer les détails internes ou les informations confidentielles.

Dans la prochaine leçon, vous protégerez les routes sensibles contre les abus en ajoutant des limites d’utilisation.

Envie d'aller plus loin ?

Les cours Enovatic sont gratuits et le resteront. Si vous cherchez un accompagnement encadré, nos formations professionnelles sont animées par les mêmes formateurs.