Sécuriser un contrat API-first dès la conception
- Accueil
- Développement, applications & chaîne logicielle
- Sécuriser un contrat API-first dès la conception
Sécuriser un contrat API-first dès la conception
Section intitulée « Sécuriser un contrat API-first dès la conception »Une API (Application Programming Interface, interface de programmation applicative) n’est pas un détail d’intégration : c’est une frontière de confiance exposée à des clients, des services et, tôt ou tard, à des erreurs de conception. En API-first, le contrat doit définir ce qui est autorisé, refusé et traçable avant que le code ne transforme des suppositions en dette de sécurité.
Un contrat d’API ressemble au règlement d’accès d’un bâtiment : il indique quelles portes existent, qui peut passer, ce qui doit être présenté et ce qui sera refusé. Sans règlement précis, chaque gardien improvise. Cela paraît rapide jusqu’au jour où une porte oubliée donne accès à la salle des archives.
→ Lire l’explication complète de la marmotte
Contrat OpenAPI comme frontière de confiance
Section intitulée « Contrat OpenAPI comme frontière de confiance »Le compromis central est brutal : un contrat strict ralentit les changements improvisés, mais il empêche les consommateurs d’inventer des comportements que le service devra ensuite supporter éternellement. La recommandation est nette : traiter le contrat comme une politique de sécurité versionnée, validée en intégration continue, puis appliquée à l’entrée du service. Un fichier OpenAPI (OpenAPI Specification, spécification de description d’API) décoratif ne protège rien. Il meuble très bien une slide, ce qui est déjà une carrière respectable dans certains produits.
Le contrat doit fixer, pour chaque opération :
- l’identité attendue et le mécanisme d’authentification ;
- les droits requis, exprimés comme des capacités métier ;
- les formats de requête et de réponse ;
- les bornes de taille, de cardinalité et de pagination ;
- les codes d’erreur observables ;
- les données interdites dans les réponses ;
- les règles d’idempotence, c’est-à-dire le comportement d’une répétition de requête.
Une opération PATCH /users/{id} sans schéma fermé accepte souvent des propriétés inattendues. C’est la voie classique vers la mass assignment vulnerability : le client soumet isAdmin, tenantId ou creditLimit, puis le framework associe mécaniquement les champs reçus au modèle interne. Le contrat doit déclarer explicitement les propriétés admises et le code doit construire une commande métier dédiée. Désérialiser un objet de domaine depuis Internet revient à laisser un formulaire remplir la comptabilité, les badges d’accès et le thermostat.
Les formats doivent être canoniques là où une signature, un cache ou une comparaison porte sur le contenu. Deux représentations JSON (JavaScript Object Notation, format textuel de données) sémantiquement proches peuvent différer par l’ordre des champs, l’encodage ou la précision numérique. Pour les règles de sérialisation, les signatures et la cryptographie applicative, consulter aussi les formats, bibliothèques et API cryptographiques.
Le contrat ne doit pas exposer les modèles internes. Un identifiant technique, un état de workflow ou un champ d’audit peut être légitime dans une base, mais ne l’est pas automatiquement dans une réponse. Concevoir un modèle de lecture public distinct coûte des transformations. Ce coût est inférieur à celui d’une compatibilité accidentelle devenue contractuelle, puis impossible à retirer sans comité de crise et tableur maudit.
Authentification et autorisation au niveau de l’opération
Section intitulée « Authentification et autorisation au niveau de l’opération »L’authentification répond à « quelle identité présente la requête ? ». L’autorisation répond à « cette identité peut-elle faire cette action sur cette ressource ? ». Confondre les deux produit des API où un jeton valide devient un passe-partout. Le jeton n’est pas une permission universelle, même s’il est signé avec beaucoup d’assurance.
Pour les accès délégués, OAuth 2.0 (Open Authorization version 2.0) doit produire des jetons à durée courte, destinés à une audience précise et porteurs de droits limités. Un JWT (JSON Web Token, jeton JSON signé) doit être vérifié sur au minimum sa signature, son émetteur, son audience, son instant d’expiration et son instant de validité. Accepter un algorithme indiqué par l’en-tête du jeton sans liste locale d’algorithmes autorisés ouvre la porte aux confusions d’algorithme. La vérification doit imposer l’algorithme attendu et sélectionner la clé par un identifiant contrôlé.
Les droits doivent représenter une action métier, par exemple invoice:approve, et non une route technique telle que POST:/v1/invoices/{id}. Une route évolue ; l’intention de sécurité doit survivre à cette évolution. L’autorisation doit aussi contrôler la ressource ciblée : un droit invoice:read ne donne pas accès à toutes les factures de tous les tenants. Cette vérification de propriété doit être exécutée après résolution de la ressource et avant lecture ou mutation.
Le contrôle d’accès doit être cohérent entre API publique, tâches asynchrones et interfaces d’administration. Déplacer une opération sensible dans une file de messages ne fait pas disparaître l’autorisation, cela la déplace. Le consommateur doit recevoir l’identité ou les attributs nécessaires, protégés contre l’altération, puis réévaluer la règle. Les sujets d’identité fédérée et de cycle de vie des comptes relèvent de la gestion des identités.
Validation des entrées et surface d’attaque HTTP
Section intitulée « Validation des entrées et surface d’attaque HTTP »HTTP (Hypertext Transfer Protocol, protocole de transfert hypertexte) transporte plus que le corps JSON. Les en-têtes, paramètres de chemin, paramètres de requête, encodages, méthodes et tailles sont tous des entrées non fiables. Le contrat doit borner chacun d’eux. Une limite de 100 éléments par page, une longueur maximale de 128 caractères pour un filtre et un plafond de corps à 1 mégaoctet constituent des contrôles de disponibilité, pas de la décoration documentaire.
Valider au proxy ou à la passerelle réduit la charge inutile, mais ne dispense pas le service de valider. La passerelle peut être contournée par un réseau interne, une tâche de maintenance ou une mauvaise règle de routage. La validation de bord et la validation métier ont des responsabilités différentes : la première filtre les formes illégales, la seconde vérifie les états autorisés.
Les attaques fréquentes suivent un motif stable :
- BOLA (Broken Object Level Authorization) : modifier un identifiant de ressource et lire les données d’un autre tenant. Contre-mesure : autoriser chaque objet, pas seulement la route.
- Injection : transmettre une expression de filtre, une requête ou une structure interprétable. Contre-mesure : grammaire limitée, requêtes paramétrées et aucune concaténation vers un interpréteur.
- Rejeu : répéter une mutation après une coupure réseau ou depuis un journal compromis. Contre-mesure : clé d’idempotence liée à l’identité, à l’opération et au corps canonique, avec durée de rétention définie.
- Énumération : parcourir des identifiants prévisibles ou distinguer les erreurs. Contre-mesure : identifiants non séquentiels exposés, contrôle d’accès systématique et réponses d’erreur non révélatrices.
- Épuisement de ressources : envoyer des corps compressés, des tableaux énormes ou des recherches coûteuses. Contre-mesure : limites avant décompression, délais, quotas et coût maximal de requête.
Le chiffrement de transport protège le trajet, pas le serveur qui reçoit la requête. TLS (Transport Layer Security, protocole de sécurité des communications) et l’authentification mutuelle sont traités dans la sécurisation des canaux TLS. Une connexion chiffrée vers une opération sans autorisation reste une fuite avec un joli cadenas.
Exemple de contrat OpenAPI exécutable
Section intitulée « Exemple de contrat OpenAPI exécutable »L’exemple suivant ferme le schéma de création, impose une portée fonctionnelle et documente une clé d’idempotence. Le validateur doit être placé dans la chaîne de requête, avant le contrôleur métier. Générer seulement un client à partir de ce fichier n’applique aucune de ces règles côté serveur.
# openapi.yaml : OpenAPI 3.1, à valider avec un validateur compatible JSON Schemaopenapi: 3.1.0info: title: Billing API version: 1.0.0paths: /v1/invoices: post: security: - oauth2: [invoice:create] # Le jeton doit porter ce droit fonctionnel. parameters: - in: header name: Idempotency-Key required: true schema: type: string minLength: 16 maxLength: 128 requestBody: required: true content: application/json: schema: type: object additionalProperties: false # Refuse tenantId, status ou tout champ non déclaré. required: [customerId, amount, currency] properties: customerId: type: string pattern: '^[a-zA-Z0-9_-]{16,64}$' amount: type: integer minimum: 1 maximum: 100000000 currency: type: string enum: [EUR, CHF] responses: "201": description: Facture créée "400": description: Requête invalide "403": description: Droit ou appartenance insuffisantsLa clé d’idempotence ne doit pas être un identifiant global réutilisable. Stocker son empreinte avec l’identité, l’opération, l’empreinte du corps et la réponse produite. Si la même clé arrive avec un corps différent, renvoyer un conflit, pas une seconde interprétation créative. La conservation doit couvrir la fenêtre réaliste de rejeu, puis être purgée. Sans purge, l’idempotence devient un entrepôt de données personnel, avec facture et regrets.
Évolution, secrets et exploitation du contrat
Section intitulée « Évolution, secrets et exploitation du contrat »Une modification incompatible exige une nouvelle version ou une période de coexistence. Supprimer un champ de réponse, changer sa sémantique ou rendre obligatoire un attribut auparavant facultatif casse des clients, même si les tests du fournisseur sont verts. Le versionnement par média ou par chemin dépend surtout de la capacité des passerelles et des consommateurs à router ces variantes ; l’exigence reste identique : publier la durée de dépréciation et mesurer les appels restants avant retrait.
Les secrets de signature, certificats, jetons de service et clés d’API ne doivent jamais figurer dans le contrat, les exemples, les journaux ou les erreurs. Une rotation sans chevauchement casse les appels en vol ; une rotation avec chevauchement exige que le vérificateur accepte temporairement l’ancienne et la nouvelle clé, identifiées sans ambiguïté. Les clés privées doivent rester dans un gestionnaire de secrets ou un HSM (Hardware Security Module, module matériel de sécurité) lorsque le niveau de risque le justifie.
La supervision doit corréler identifiant de requête, identité authentifiée, opération, décision d’autorisation, code de réponse et durée. Ne pas journaliser le jeton, le corps complet ou les données personnelles par défaut. Les alertes doivent suivre les refus d’autorisation, les erreurs de validation, les dépassements de quota, les échecs de signature et les appels à des versions dépréciées.
Le contrat ne garantit ni la sécurité du code métier, ni l’absence de fraude, ni la confidentialité des données stockées, ni la disponibilité face à une saturation réseau. Ces propriétés viennent respectivement des revues et tests de sécurité, des contrôles métier, du chiffrement et de la gestion des clés, puis de l’architecture réseau et de capacité. Une spécification n’est pas un talisman. C’est une règle exécutable, ce qui est déjà beaucoup plus rare.
🐝 Ce qui arrive si on s’en passe
Section intitulée « 🐝 Ce qui arrive si on s’en passe »Sans contrat d’API qui définit à l’avance ce qui est autorisé, refusé et tracé, chaque implémentation improvise ses propres règles d’accès. Les suppositions non écrites se transforment en dette de sécurité : un point d’entrée oublié reste exposé, un champ qui ne devait jamais sortir fuit dans une réponse, une méthode non prévue est acceptée faute d’avoir été explicitement interdite. La frontière de confiance devient floue, car rien ne dit quel appelant a le droit de faire quoi ni ce qui doit être journalisé. La conséquence est une surface d’attaque découverte au fil des incidents plutôt qu’au moment de la conception, et des contrôles incohérents d’un service à l’autre parce que chaque gardien interprète le règlement à sa façon. Une porte non documentée finit par donner accès à des données que personne n’avait décidé d’exposer.
🦫 Explication de la marmotte 🍫
Section intitulée « 🦫 Explication de la marmotte 🍫 »Une interface de programmation permet à un programme de demander quelque chose à un autre programme. Le contrat décrit à l’avance les demandes acceptées : les chemins disponibles, les informations attendues, leur format, leur taille et les réponses possibles. Il doit aussi indiquer quelle identité peut appeler chaque action et quelles actions cette identité a le droit de réaliser.
Quand une demande arrive, le système vérifie d’abord sa forme. Un champ inconnu, un texte trop long ou un nombre hors limite doit être refusé. Ensuite, il vérifie l’identité présentée par la demande. Cette identité est généralement prouvée par un jeton signé et limité dans le temps. Le système contrôle alors le droit demandé et vérifie que la ressource visée appartient bien au bon utilisateur ou au bon groupe.
Pour une action qui modifie une donnée, une clé de répétition évite de créer deux fois le même résultat si la demande est renvoyée après une panne réseau. Le système mémorise alors le résultat pendant une durée définie.
Le contrat doit évoluer avec prudence : retirer un champ ou changer son sens peut casser les programmes qui l’utilisent. Les secrets servant à prouver les identités doivent être renouvelés sans les écrire dans les journaux. Enfin, les événements de refus, d’erreur et de surcharge doivent être surveillés. Le contrat réduit les erreurs d’accès, mais il ne corrige pas seul un programme métier défaillant, une base de données mal protégée ou un réseau indisponible.
À lire aussi
- Sécuriser une API gateway comme point de contrôleArchitecture de sécurité d'une API gateway comme point de contrôle centralisé, avec ses limites, ses attaques et ses conditions d'exploitation.
- Principes et architecture de l'événementielConcevoir une architecture événementielle fiable : contrats, livraison, cohérence, sécurité, exploitation et documentation.
- JWS : signer et sécuriser vos échanges JSONArchitecture, validation et exploitation de JSON Web Signature (JWS) pour signer des jetons et messages JSON sans confondre intégrité, identité et confidentialité.
- Attaque par confusion de scope OAuthDémonstration d’une élévation de périmètre OAuth causée par des scopes trop larges et exploitation d’un jeton d’accès compromis.
Pages voisines
La citent
- Threat modeling STRIDE avant écrire le code
- Démonstration de pollution de prototype JavaScript
- Monolithe ou microservices : choisir sans se mentir
Sécuriser un contrat API-first dès la conception
Elle cite
