Explique les 10 risques de sécurité les plus critiques spécifiques aux API et comment les atténuer.
Classement des risques de sécurité spécifiques aux API publié par l'OWASP (Open Worldwide Application Security Project). L'édition 2023 fournit la dernière liste reflétant les menaces qui ont augmenté avec l'adoption généralisée des API.
Une vulnérabilité qui permet un accès non autorisé aux données d'autres utilisateurs en manipulant les identifiants d'objets. Il s'agit de la vulnérabilité la plus fréquente et la plus facile à exploiter.
Les attaquants peuvent accéder aux informations personnelles d'autres utilisateurs, aux détails de paiement, à l'historique des commandes et à bien d'autres choses encore, simplement en modifiant l'identifiant dans l'URL ou les paramètres de la requête.
// Reçoit l'identifiant et renvoie les données directement - pas de contrôle d'autorisation app.get('/api/users/:id/orders', async (req, res) => { const orders = await Order.find({ userId: req.params.id }); res.json(orders); });
// Vérifier l'identité de l'utilisateur authentifié pour le contrôle de l'autorisation app.get('/api/users/:id/orders', authenticate, async (req, res) => { if (req.user.id !== req.params.id && !req.user.isAdmin) { return res.status(403).json({ error: 'Forbidden' }); } const orders = await Order.find({ userId: req.params.id }); res.json(orders); });
Une vulnérabilité qui permet à des attaquants de prendre le contrôle de comptes d'utilisateurs légitimes en raison d'implémentations défectueuses du mécanisme d'authentification.
Politiques de mot de passe insuffisantes, mauvaise gestion des jetons, absence de protection par force brute, gestion inadéquate des sessions, etc.
const jwt = require('jsonwebtoken'); function authenticate(req, res, next) { const token = req.headers.authorization?.split(' ')[1]; if (!token) return res.status(401).json({ error: 'Token required' }); try { // Spécifier explicitement l'algorithme (empêche l'attaque alg : none) const decoded = jwt.verify(token, process.env.JWT_SECRET, { algorithms: ['HS256'], issuer: 'your-app', }); req.user = decoded; next(); } catch (err) { res.status(401).json({ error: 'Invalid token' }); } }
Une vulnérabilité où le contrôle d'accès sur les propriétés (champs) des objets inclus dans les réponses de l'API est insuffisant. Cet élément combine l'exposition excessive aux données et l'assignation en masse.
// Retourne uniquement les champs publics de l'objet utilisateur function sanitizeUser(user, requesterId) { const publicFields = { id: user.id, name: user.name, avatar: user.avatar }; // Seul le propriétaire peut voir les champs supplémentaires if (requesterId === user.id) { publicFields.email = user.email; publicFields.phone = user.phone; } return publicFields; // ❌ retourner l'utilisateur ; fuite du password_hash, etc. }
Une vulnérabilité où il n'y a pas de limites à la taille, à la fréquence ou à la consommation de ressources des requêtes API, ce qui conduit à des attaques DoS ou à des augmentations de coûts.
const rateLimit = require('express-rate-limit'); // Limitation globale du débit app.use(rateLimit({ windowMs: 15 * 60 * 1000, // 15 minutes max: 100, // Maximum 100 demandes standardHeaders: true, })); // Limite de la taille de la charge utile app.use(express.json({ limit: '10kb' })); // Limite supérieure de la pagination app.get('/api/items', (req, res) => { const limit = Math.min(parseInt(req.query.limit) || 20, 100); // ... });
Une vulnérabilité dans laquelle un contrôle d'accès approprié n'est pas mis en œuvre pour les fonctions d'administration et les points de terminaison, ce qui permet à des utilisateurs ordinaires d'effectuer des opérations d'administration.
function authorize(...roles) { return (req, res, next) => { if (!roles.includes(req.user.role)) { return res.status(403).json({ error: 'Insufficient permissions' }); } next(); }; } // Accès réservé aux administrateurs app.delete('/api/admin/users/:id', authenticate, authorize('admin'), deleteUser); // Admin et modérateur app.put('/api/posts/:id/moderate', authenticate, authorize('admin', 'moderator'), moderatePost);
Vulnérabilité dans laquelle les flux logiques critiques ne sont pas protégés contre les attaques automatisées. Exemples : vente de billets à la sauvette, récolte massive de coupons, envoi de spam, etc.
Une vulnérabilité dans laquelle le serveur récupère une URL fournie par l'utilisateur sans validation, ce qui permet un accès non autorisé aux réseaux internes.
const { URL } = require('url'); function isAllowedUrl(input) { try { const url = new URL(input); // Restreindre les protocoles if (!['https:', 'http:'].includes(url.protocol)) return false; // Bloquer les plages d'adresses IP privées const blocked = ['127.0.0.1', 'localhost', '0.0.0.0', '169.254.169.254']; if (blocked.includes(url.hostname)) return false; // Vérifier les plages de réseaux internes (10.x, 172.16-31.x, 192.168.x) if (/^(10\.|172\.(1[6-9]|2\d|3[01])\.|192\.168\.)/.test(url.hostname)) return false; return true; } catch { return false; } }
Paramètres de sécurité inappropriés sur les serveurs API ou les frameworks. Il s'agit notamment de l'autorisation de méthodes HTTP inutiles, de politiques CORS trop permissives, de l'exposition d'informations de débogage, etc.
const helmet = require('helmet'); const cors = require('cors'); app.use(helmet()); app.use(cors({ origin: ['https://app.example.com'], // Ne pas utiliser de caractères génériques methods: ['GET', 'POST', 'PUT', 'DELETE'], credentials: true, })); // Gestionnaire d'erreurs : ne pas renvoyer les traces de la pile en production app.use((err, req, res, next) => { res.status(500).json({ error: process.env.NODE_ENV === 'production' ? 'Internal Server Error' : err.message, }); });
État dans lequel d'anciennes versions de points d'extrémité d'API sont exposées sans que des correctifs de sécurité aient été appliqués. Également connu sous le nom d'API fantômes ou d'API zombies.
Une vulnérabilité dans laquelle les réponses d'API tierces sont acceptées sans validation. Si une API externe est compromise, l'impact se propage à votre propre système.
const Ajv = require('ajv'); const ajv = new Ajv(); // Valider les réponses de l'API externe à l'aide d'un schéma const externalSchema = { type: 'object', required: ['id', 'status'], properties: { id: { type: 'string', maxLength: 50 }, status: { type: 'string', enum: ['active', 'inactive'] }, }, additionalProperties: false, }; const validate = ajv.compile(externalSchema); async function fetchExternalData() { const res = await fetch('https://api.external.com/data'); const data = await res.json(); if (!validate(data)) { throw new Error('External API response validation failed'); } return data; }
| ID | Vulnérabilité | Sévérité | Principales mesures d'atténuation |
|---|---|---|---|
| API1 | Broken Object Level Authorization | Critical | Contrôles des autorisations au niveau des objets |
| API2 | Broken Authentication | Critical | Gestion adéquate des jetons et protection par force brute |
| API3 | Broken Object Property Level Authorization | High | Filtrage des champs de réponse explicite |
| API4 | Unrestricted Resource Consumption | High | Limitation du débit et de la taille de la charge utile |
| API5 | Broken Function Level Authorization | High | Contrôle d'accès basé sur les rôles |
| API6 | Unrestricted Access to Sensitive Business Flows | Medium | CAPTCHA et limitation des taux au niveau de l'entreprise |
| API7 | Server Side Request Forgery | High | Validation des URL et blocage des IP privées |
| API8 | Security Misconfiguration | Medium | En-têtes de sécurité et configuration CORS |
| API9 | Improper Inventory Management | Medium | Gestion de l'inventaire des API et politiques d'obsolescence |
| API10 | Unsafe Consumption of APIs | Medium | Validation du schéma des réponses de l'API externe |