Chapitre 1 · Leçon 3
IDOR, escalade de privilèges et contrôle d'accès
Section 1
Step 1
IDOR : accéder à une ressource qui appartient à un autre utilisateur en changeant simplement l'ID dans l'URL. C'est la vulnérabilité #1 selon OWASP 2021.
snippet.typescript
1// ❌ Endpoint vulnérable à l'IDOR
2app.get('/api/invoices/:id', authenticate, async (req, res) => {
3 const invoice = await prisma.invoice.findUnique({
4 where: { id: req.params.id },
5 });
6 res.json(invoice);
7 // Si je suis l'utilisateur 42 et que je demande /api/invoices/99,
8 // je reçois la facture de l'utilisateur 99 !
9});
10
11// ✅ Correction : toujours filtrer par l'utilisateur authentifié
12app.get('/api/invoices/:id', authenticate, async (req, res) => {
13 const invoice = await prisma.invoice.findFirst({
14 where: {
15 id: req.params.id,
16 userId: req.user.id, // ← LA LIGNE ESSENTIELLE
17 },
18 });
19
20 if (!invoice) {
21 // Ne pas révéler si la ressource existe (404 même si 403)
22 return res.status(404).json({ error: "Facture introuvable" });
23 }
24
25 res.json(invoice);
26});
27
28// ✅ Middleware de vérification réutilisable
29async function requireOwnership(
30 req: Request,
31 res: Response,
32 next: NextFunction
33) {
34 const resource = await prisma.invoice.findUnique({
35 where: { id: req.params.id },
36 select: { userId: true },
37 });
38
39 if (!resource || resource.userId !== req.user.id) {
40 return res.status(404).json({ error: "Introuvable" });
41 }
42
43 next();
44}
45
46app.delete('/api/invoices/:id', authenticate, requireOwnership, async (req, res) => {
47 await prisma.invoice.delete({ where: { id: req.params.id } });
48 res.status(204).send();
49});