Validez à la frontière et ne faites confiance à rien qui la traverse
L'affirmation La plupart des bogues applicatifs et une large part des failles de sécurité viennent de la même cause racine : des données entrées dans le système sous une forme que...
L'affirmation
La plupart des bogues applicatifs et une large part des failles de sécurité viennent de la même cause racine : des données entrées dans le système sous une forme que le code n'attendait pas, et auxquelles il a fait confiance quand même parce que rien ne les avait vérifiées au point d'arrivée. Le correctif est une discipline, pas une bibliothèque — validez chaque entrée à la frontière où elle entre dans votre système, rejetez ce qui ne se conforme pas avant que cela ne touche la moindre logique, et traitez tout ce qui a franchi la frontière comme sûr pour que l'intérieur n'ait jamais à deviner.
Ce que « la frontière » signifie
La frontière est chaque point où des données hors de votre contrôle entrent dans votre code : un corps de requête HTTP, un paramètre d'URL, un fichier téléversé, un message d'une file, un rappel HTTP d'un tiers, une ligne relue d'une intégration que vous ne possédez pas. Tout ce qui provient de l'extérieur de votre programme est non fiable au moment de son arrivée, quelle que soit l'amabilité apparente de la source — un rappel HTTP d'un fournisseur de paiement de confiance peut tout de même être malformé, rejoué ou falsifié, et une valeur envoyée par votre propre application mobile peut avoir été altérée en transit par quelqu'un utilisant votre API directement.
L'erreur est de valider au milieu plutôt qu'à la bordure : une vérification enfouie trois appels de fonction plus loin, après que les mauvaises données ont déjà été promenées, journalisées et utilisées pour prendre une décision. À ce moment, le dommage est contextuel et difficile à retracer. La validation appartient à la porte d'entrée, avant que les données ne soient admises où que ce soit.
Analysez, ne vous contentez pas de vérifier
La forme la plus forte de validation à la frontière ne se contente pas de vérifier qu'une entrée est acceptable puis de transmettre la valeur d'origine encore lâche — elle transforme l'entrée en un type interne précis qui ne peut pas représenter les états invalides. Vous ne vérifiez pas qu'une chaîne ressemble à un courriel pour ensuite continuer à passer la chaîne ; vous l'analysez en une valeur Email, et tout en aval reçoit ce type, qui par son existence garantit la validité.
// a la frontiere : analyser en une forme precise, rejeter en cas d'echec
const parsed = OrderSchema.safeParse(request.body);
if (!parsed.success) {
return respond(422, { errors: parsed.error.issues });
}
// passe cette ligne, `parsed.data` est sur et correctement type.
// rien en aval ne le reverifie, car il ne peut pas etre faux.
const order = parsed.data;
L'avantage est que la validation a lieu exactement une fois, en un seul endroit, et tout l'intérieur de votre application est libéré de la vérification défensive. Une fonction au fond du système qui reçoit un objet Order n'a pas à se demander si le total est négatif ou le courriel malformé, car ces états ont été rendus irreprésentables à la frontière. C'est ce qui fait passer la discipline à l'échelle : les vérifications sont concentrées, pas éparpillées.
Rejetez tôt, rejetez précisément
Quand une entrée échoue à la validation, la réponse devrait être immédiate et précise. Renvoyez un statut d'erreur cliente — 422 pour une requête bien formée au contenu invalide, 400 pour une requête malformée — et nommez ce qui n'allait pas, champ par champ, pour que l'appelant puisse corriger. Un échec de validation qui renvoie un 500 générique est un mensonge : il dit à l'appelant que votre serveur s'est brisé alors que c'est son entrée qui l'était, et il envoie votre équipe enquêter sur une panne serveur fantôme. La règle est que la mauvaise entrée est l'erreur du client et doit être rapportée comme telle, assez clairement pour qu'il corrige sans deviner.
Validez les valeurs, pas seulement la forme
La validation structurelle — les bons champs, les bons types — est nécessaire mais insuffisante. La frontière doit aussi imposer les contraintes d'affaires qui rendent une valeur sensée : une quantité positive, une date qui n'est pas passée pour une réservation, un rabais qui ne dépasse pas le total, un code de pays qui en est un où vous livrez réellement. Ce sont les vérifications qui attrapent l'entrée techniquement bien formée mais sémantiquement impossible, et elles appartiennent à la frontière aux côtés des vérifications structurelles, car un intérieur qui fait confiance à la frontière lui fait confiance pour le sens autant que pour la forme.
quantity: entier, >= 1, <= 999
ship_to: doit etre dans l'ensemble des pays servis
total: doit egaler la somme des postes (recalculer, jamais faire confiance)
Cette dernière ligne est celle que les équipes sautent le plus souvent : ne faites jamais confiance à un total, un prix ou toute valeur que le client aurait pu manipuler à son avantage. Recalculez l'argent côté serveur à partir de données faisant autorité, et traitez la version du client comme une prétention à vérifier, pas un fait à utiliser.
La dimension sécurité
La validation à la frontière est aussi le fondement sous la plupart des défenses contre l'injection. Des données validées et analysées en une valeur typée à la frontière, puis manipulées par des requêtes paramétrées et un encodage de sortie tenant compte du contexte, ne deviennent pas une injection SQL ou une faille de script intersite, car elles ne sont jamais concaténées comme texte brut à un endroit où elles pourraient être interprétées comme du code. La discipline qui garde votre logique correcte est la même qui la garde sûre : l'entrée non fiable est contenue et transformée à la bordure, et l'intérieur ne manipule jamais que des valeurs dont la forme et le sens sont déjà garantis.
La règle en une ligne
Chaque donnée qui franchit vers votre système est validée et analysée au point de son arrivée, est rejetée clairement si elle ne se conforme pas, et est ensuite pleinement digne de confiance parce qu'elle l'a mérité. Une application bâtie ainsi a un seul endroit où regarder quand l'entrée est mauvaise, un intérieur qui ne se remet jamais en question, et toute une catégorie de bogues et de vulnérabilités qui ne peuvent tout simplement pas survenir parce que les états invalides ont été refusés à la porte.