codanalystBlog
Tous les articles
Sécurité

Sécuriser une API REST : 7 vulnérabilités courantes et comment les prévenir

Découvrez 7 vulnérabilités courantes des API REST, avec des exemples pratiques en C# et ASP.NET Core. Apprenez à prévenir les failles de contrôle d'accès, les injections SQL, les erreurs de validation, l'exposition de données sensibles et les abus de requêtes grâce aux bonnes pratiques de sécurité.

L'équipe Codanalyst

6 min de lecture

Sécuriser une API REST : 7 vulnérabilités courantes et comment les prévenir
Sommaire
  1. 011. Contrôle d'accès défaillant : la faille BOLA
  2. 022. Authentification mal configurée
  3. 033. Injection SQL
  4. 044. Validation insuffisante des données
  5. 055. Exposition excessive de données
  6. 066. Absence de limitation des requêtes
  7. 077. Gestion incorrecte des erreurs
  8. 08Vérifier une API avant sa mise en production
  9. 09Conclusion

Une API REST peut fonctionner correctement, respecter les conventions HTTP et retourner des réponses JSON parfaitement structurées, tout en exposant des données sensibles ou en permettant des opérations non autorisées.

Le problème ne vient pas toujours d'une faille complexe. Parfois, une simple vérification oubliée dans un contrôleur suffit à compromettre la sécurité de toute une fonctionnalité.

Prenons un exemple : une API permet à ses utilisateurs de consulter leurs commandes. L'authentification fonctionne, les tokens sont valides et les requêtes sont correctement traitées.

Pourtant, si un utilisateur peut consulter les commandes d'un autre en modifiant simplement un identifiant dans l'URL, l'application présente une faille de contrôle d'accès.

C'est ce type de problème que nous allons examiner dans cet article.

Ce que vous allez apprendre : identifier sept catégories de vulnérabilités, comprendre comment elles apparaissent dans le code et découvrir les mesures à appliquer pour mieux protéger une API REST.

1. Contrôle d'accès défaillant : la faille BOLA

BOLA signifie Broken Object Level Authorization. On rencontre également le terme IDOR pour désigner certains problèmes similaires.

Cette vulnérabilité apparaît lorsqu'une API vérifie qu'un utilisateur est connecté, mais ne vérifie pas correctement s'il a le droit d'accéder à la ressource demandée.

Exemple de code vulnérable

Imaginons un endpoint qui récupère une commande par son identifiant :

[HttpGet("{id:int}")]
public async Task<IActionResult> GetOrder(int id)
{
    var order = await _dbContext.Orders
        .FindAsync(id);

    if (order is null)
        return NotFound();

    return Ok(order);
}

Le problème est simple : aucune vérification ne garantit que la commande appartient à l'utilisateur connecté.

Si un utilisateur connaît l'identifiant d'une autre commande, il pourrait obtenir des informations auxquelles il ne devrait pas avoir accès.

Comment corriger ce problème ?

Pour un utilisateur qui ne doit accéder qu'à ses propres commandes, on peut filtrer directement la requête :

[Authorize]
[HttpGet("{id:int}")]
public async Task<IActionResult> GetOrder(int id)
{
    var userId = User.FindFirst(
        System.Security.Claims.ClaimTypes.NameIdentifier
    )?.Value;

    if (userId is null)
        return Unauthorized();

    var order = await _dbContext.Orders
        .FirstOrDefaultAsync(o =>
            o.Id == id &&
            o.UserId == userId);

    if (order is null)
        return NotFound();

    return Ok(order);
}

Cette version limite la recherche aux commandes de l'utilisateur authentifié. Dans une application réelle, adaptez la logique aux règles métier et aux éventuels rôles autorisés.

2. Authentification mal configurée

L'authentification permet de déterminer l'identité d'un utilisateur ou d'un service. Lorsqu'elle est mal implémentée, une API peut accepter des requêtes provenant d'acteurs qui ne devraient pas y accéder.

Dans ASP.NET Core, un endpoint privé peut être protégé avec l'attribut [Authorize] :

[Authorize]
[HttpGet("profile")]
public IActionResult GetProfile()
{
    return Ok(new
    {
        Message = "Accès autorisé"
    });
}

Mais l'attribut ne suffit pas à lui seul : le mécanisme d'authentification doit être correctement configuré.

Pour une API utilisant JWT, vérifiez notamment :

  • la signature du token ;
  • sa date d'expiration ;
  • l'émetteur (issuer) ;
  • l'audience (audience) ;
  • les algorithmes et clés autorisés ;
  • les rôles et permissions effectivement accordés.

Il faut également prévoir une politique adaptée aux tentatives de connexion, à la récupération des comptes et à la révocation des sessions lorsque l'architecture le permet.

3. Injection SQL

Une injection SQL survient lorsque des données contrôlées par un utilisateur modifient la structure d'une requête SQL.

Le risque est particulièrement important lorsqu'une application construit manuellement ses requêtes en concaténant des chaînes.

Mauvaise pratique

var sql =
    "SELECT * FROM Users WHERE Email = '" +
    email + "'";

Ici, la valeur de email est intégrée directement dans la requête.

Une entrée inattendue pourrait modifier la logique SQL exécutée par le serveur.

Approche recommandée

Avec Entity Framework Core, privilégiez les requêtes LINQ :

var user = await _dbContext.Users
    .FirstOrDefaultAsync(u => u.Email == email);

L'ORM génère une requête paramétrée adaptée au fournisseur de base de données.

Si vous utilisez du SQL brut, veillez à transmettre les valeurs comme paramètres plutôt que de les concaténer dans la requête.

4. Validation insuffisante des données

Une API ne doit jamais supposer que les données reçues du client sont valides.

Même si le frontend impose des contraintes, un client peut envoyer directement une requête HTTP avec des données différentes.

Considérons un endpoint de création d'utilisateur.

Définir des règles de validation

using System.ComponentModel.DataAnnotations;

public class CreateUserRequest
{
    [Required]
    [EmailAddress]
    public string Email { get; set; } = string.Empty;

    [Required]
    [StringLength(100, MinimumLength = 2)]
    public string Name { get; set; } = string.Empty;
}

Avec un contrôleur ASP.NET Core décoré par [ApiController], les erreurs de validation du modèle déclenchent normalement une réponse HTTP 400 automatique.

[ApiController]
[Route("api/users")]
public class UsersController : ControllerBase
{
    [HttpPost]
    public IActionResult Create(CreateUserRequest request)
    {
        return Ok(new
        {
            request.Email,
            request.Name
        });
    }
}

Cet exemple illustre la validation de forme et de longueur. Les règles métier — par exemple, vérifier qu'un email est unique — doivent être appliquées séparément.

5. Exposition excessive de données

Une API peut renvoyer beaucoup plus d'informations que le client n'en a besoin.

Imaginons un endpoint qui renvoie directement une entité de base de données :

return Ok(user);

Si cette entité contient un champ interne ou confidentiel, il risque d'être exposé dans la réponse JSON selon la configuration de sérialisation.

Utiliser un DTO dédié

public sealed record UserResponse(
    int Id,
    string Name,
    string Email
);

Puis construire explicitement la réponse :

var response = new UserResponse(
    user.Id,
    user.Name,
    user.Email
);

return Ok(response);

Le DTO définit clairement les champs destinés au client. Cette approche évite d'exposer accidentellement tous les champs du modèle interne.

6. Absence de limitation des requêtes

Certains endpoints sont particulièrement sensibles à l'abus : connexion, récupération de mot de passe, envoi de SMS, génération de codes et opérations coûteuses.

Sans limitation, une API peut subir une surcharge, des tentatives répétées ou des coûts inattendus.

ASP.NET Core propose un middleware de limitation du débit (rate limiting).

Exemple de configuration

using System.Threading.RateLimiting;

builder.Services.AddRateLimiter(options =>
{
    options.AddFixedWindowLimiter("api", limiter =>
    {
        limiter.PermitLimit = 60;
        limiter.Window = TimeSpan.FromMinutes(1);
        limiter.QueueLimit = 0;
        limiter.AutoReplenishment = true;
    });
});

Activez le middleware dans le pipeline :

app.UseRateLimiter();

Vous pouvez ensuite appliquer la politique aux endpoints concernés :

[EnableRateLimiting("api")]
[HttpGet("catalog")]
public IActionResult GetCatalog()
{
    return Ok();
}

Cette politique d'exemple autorise 60 requêtes par minute pour chaque partition configurée. Elle doit être adaptée au trafic attendu et aux caractéristiques du service.

7. Gestion incorrecte des erreurs

Les erreurs sont utiles pour diagnostiquer un problème, mais les détails internes ne doivent pas être divulgués inutilement aux clients.

Une réponse comme celle-ci est inadaptée en production :

System.NullReferenceException
at MyApplication.Services.OrderService.GetOrder(...)
C:\Build\MyApplication\OrderService.cs

Elle peut révéler des détails sur l'architecture et l'environnement de déploiement.

Préférer une réponse contrôlée

{
  "error": "An unexpected error occurred.",
  "traceId": "example-trace-id"
}

L'identifiant de corrélation doit permettre de retrouver l'événement dans les journaux internes, sans exposer la stack trace au client.

En production :

  • désactivez les pages d'erreur détaillées ;
  • évitez d'enregistrer des tokens et secrets en clair ;
  • protégez l'accès aux logs ;
  • conservez le contexte nécessaire au diagnostic ;
  • utilisez des réponses d'erreur cohérentes.

Vérifier une API avant sa mise en production

Une revue de sécurité efficace ne consiste pas seulement à chercher des erreurs dans le code. Elle doit également vérifier le comportement réel de l'API.

Pour chaque endpoint, posez-vous les questions suivantes :

  • Qui peut appeler cette route ?
  • Quelles ressources cette personne peut-elle consulter ou modifier ?
  • Les données reçues sont-elles validées côté serveur ?
  • La réponse contient-elle uniquement les informations nécessaires ?
  • Les abus et les erreurs sont-ils correctement gérés ?
  • Les tests couvrent-ils les accès autorisés et refusés ?

Pour approfondir ces contrôles, consultez les ressources officielles :

Conclusion

Sécuriser une API REST ne se résume pas à vérifier un token ou à ajouter quelques attributs dans les contrôleurs.

Il faut appliquer des contrôles cohérents à chaque étape : authentification, autorisation, validation des entrées, accès aux données, exposition des réponses et gestion du trafic.

Les sept vulnérabilités présentées constituent un point de départ pour améliorer la sécurité d'une API existante ou concevoir une nouvelle application.

La règle à retenir : toute donnée reçue du client doit être considérée comme non fiable, et toute opération sensible doit être autorisée explicitement côté serveur.

La sécurité doit faire partie de la conception, du développement, des tests et du déploiement — pas seulement d'une vérification effectuée à la fin du projet.

Cet article vous a été utile ?

Partagez-le avec votre équipe.

inX

Commentaires

Les commentaires sont relus avant publication.

    Laisser un commentaire

    À lire ensuite

    Bêta privée

    Soyez parmi les premiers

    Laissez votre adresse : nous vous préviendrons dès l'ouverture de la bêta. Gratuite, sans engagement et sans carte bancaire.

    Un seul e-mail : celui qui vous annoncera l'ouverture de la bêta. Désinscription sur simple demande. Voir notre politique de confidentialité.

    • Gratuit
    • Sans engagement
    • Aucun spam