Retour au blog
#API#Sécurité#OWASP#BOLA#GraphQL#REST#Tutorial

Sécuriser ses API REST/GraphQL — Bonnes pratiques essentielles

LLLEBONI BAKLA Lionel•📅 15 avril 2026• ⏱️ 11 min

Pendant six mois, j’ai testé plusieurs environnements vulnérables (CRAPI, VAPI, DVGA) et accompagné des équipes de développement sur la sécurisation de leurs API. Voici une synthèse des vulnérabilités les plus fréquentes — et surtout comment les corriger.

Le paysage des risques API

L’OWASP API Security Top 10 reste la référence. Les trois failles que je rencontre le plus souvent :

# Vulnérabilité Fréquence
1 Broken Object Level Authorization (BOLA) 🔴 Très élevée
2 Injection (SQL, NoSQL, command) 🔴 Élevée
3 Broken Authentication 🟡 Moyenne

1. BOLA — Broken Object Level Authorization

Le problème

Un utilisateur accède à /api/orders/123 — mais rien ne vérifie qu’il est bien le propriétaire de la commande 123. Il lui suffit de changer le 123 en 124, 125… pour lire les données des autres.

C’est l’équivalent API de l’IDOR web. C’est la vulnérabilité la plus courante sur les API.

Démo (style CRAPI)

GET /api/orders/1001 HTTP/1.1
Authorization: Bearer <token_user_A>

→ Réponse : données de la commande 1001 (appartenant à user_A). ✅

GET /api/orders/1002 HTTP/1.1
Authorization: Bearer <token_user_A>

→ Réponse : données de la commande 1002 (appartenant à user_B). ❌ BOLA !

Le correctif

Toujours vérifier l’ownership côté serveur — jamais faire confiance au client.

// ❌ MAL
app.get('/api/orders/:id', auth, async (req, res) => {
  const order = await Order.findById(req.params.id);
  res.json(order);
});

// ✅ BIEN
app.get('/api/orders/:id', auth, async (req, res) => {
  const order = await Order.findOne({
    _id: req.params.id,
    userId: req.user.id, // ownership check
  });
  if (!order) return res.status(404).json({ error: 'Not found' });
  res.json(order);
});

2. Injections

SQL Injection

Toujours utiliser des requêtes paramétrées :

// ❌ MAL — concatenation
const q = `SELECT * FROM users WHERE name = '${name}'`;

// ✅ BIEN — paramétré
const q = 'SELECT * FROM users WHERE name = $1';
db.query(q, [name]);

NoSQL Injection (MongoDB)

Inscription : {"username": {"$ne": null}} peut matcher tous les users !

// ❌ MAL
User.find({ username: req.body.username });

// ✅ BIEN — valider le type
if (typeof req.body.username !== 'string') {
  return res.status(400).json({ error: 'Invalid' });
}

GraphQL — Depth & Complexity

Sur GraphQL (DVGA en demo), les attaques par profondeur et complexité peuvent DoSer le serveur :

# Bomb récursive
query { user { friends { user { friends { user { ... } } } } } }

Fix : limiter la profondeur et le coût des requêtes.

import depthLimit from 'graphql-depth-limit';
import costAnalysis from 'graphql-cost-analysis';

const server = new ApolloServer({
  typeDefs,
  resolvers,
  validationRules: [
    depthLimit(5),
    costAnalysis({ maximumCost: 1000 }),
  ],
});

3. Authentification faible

JWT — pièges classiques

// ❌ NE JAMAIS FAIRE
const decoded = jwt.decode(token);
if (decoded.admin) { /* grant admin */ }

// ✅ TOUJOURS VÉRIFIER LA SIGNATURE
const decoded = jwt.verify(token, SECRET);

Erreurs que je vois souvent :

  • alg: none accepté
  • Secret faible partagé
  • JWT sans expiration
  • Refresh token non rotatif

Rate limiting

Sans rate limit, brute-force garanti :

import rateLimit from 'express-rate-limit';

const loginLimiter = rateLimit({
  windowMs: 15 * 60 * 1000,
  max: 5,
  message: 'Too many attempts',
});

app.post('/api/login', loginLimiter, loginHandler);

4. Mass Assignment

Un user envoie un champ non prévu (role: 'admin') et votre code fait User.create(req.body).

// ❌ MAL
const user = await User.create(req.body);

// ✅ BIEN — whitelist
const { username, email, password } = req.body;
const user = await User.create({ username, email, password });

5. CORS mal configuré

// ❌ DANGER
app.use(cors({ origin: '*' }));

// ✅ SAFE
app.use(cors({
  origin: ['https://app.mondomaine.com'],
  credentials: true,
}));

Checklist fin de développement

Avant de mettre une API en prod :

  • Authorization vérifiée sur chaque endpoint sensible
  • Requêtes paramétrées partout (zéro concaténation SQL)
  • Validation des inputs (zod, joi, class-validator)
  • Rate limiting sur login, register, reset password
  • JWT avec secret fort, expiration courte, rotation refresh
  • HTTPS obligatoire, HSTS activé
  • Logs de sécurité (échecs d’auth, accès refusés)
  • CORS restrictif
  • Headers : CSP, X-Content-Type-Options, X-Frame-Options
  • Tests avec des outils (Burp, OWASP ZAP, nuclei)

Outils que je recommande

Outil Usage
Burp Suite Proxy, scanner, intruder
OWASP ZAP Scanner gratuit, automatisation CI/CD
nuclei Templates CVE, détection en masse
ffuf Fuzzing de endpoints et params
graphql-playground Introspection et tests GraphQL
jwt_tool Analyse et forge de JWT

Conclusion

90% des vulnérabilités API que je trouve viennent d’un mauvais modèle d’autorisation (BOLA) ou d’une validation d’input absente. Ces deux points couverts correctement éliminent l’essentiel du risque.

La sécurité API n’est pas un sujet “en plus” — c’est un axe à intégrer dès la conception, et à tester continuellement via des scans automatisés dans vos pipelines CI/CD.

“Une API sécurisée n’est pas une API qui ne fait rien. C’est une API qui refuse bien.”

À propos de l'auteur

LEBONI BAKLA Lionel — Ingénieur en Cybersécurité & IA Appliquée. Ethical Hacker • Bug Hunter • DevSecOps Junior • FullStack Developer.