Décompression de la requête dans ASP.NET Core

Par David Acker

Intergiciel de décompression de requête :

  • Permet aux points de terminaison d’API d’accepter les requêtes avec du contenu compressé.
  • Utilise l’en-tête HTTP Content-Encoding pour identifier et décompresser automatiquement les requêtes qui contiennent du contenu compressé.
  • Élimine la nécessité d’écrire du code pour gérer les requêtes compressées.

Lorsque la valeur d’en-tête Content-Encoding d’une requête correspond à l’un des fournisseurs de décompression disponibles, l’intergiciel :

  • Utilise le fournisseur de correspondance pour encapsuler le HttpRequest.Body dans un flux de décompression approprié.
  • Supprime l’en-tête Content-Encoding, indiquant que le corps de la requête n’est plus compressé.

Les demandes qui n’incluent pas d’en-tête Content-Encoding sont ignorées par l’intergiciel de décompression des requêtes.

Décompression :

  • Se produit lorsque le corps de la requête est lu. Autrement dit, la décompression se produit au niveau du point de terminaison sur la liaison de données. Le corps de la demande n’est pas compressé avec impatience.
  • Lorsque vous tentez de lire le corps de la demande compressée avec des données compressées non valides pour le Content-Encodingspécifié, une exception est levée. Brotli peut lever System.InvalidOperationException: Decoder ran into invalid data. Deflate et GZip peuvent lever System.IO.InvalidDataException: The archive entry was compressed using an unsupported compression method.

Si l’intergiciel rencontre une requête avec du contenu compressé mais ne peut pas la décompresser, la demande est transmise au délégué suivant dans le pipeline. Par exemple, une requête avec une valeur d’en-tête Content-Encoding non prise en charge ou plusieurs valeurs d’en-tête Content-Encoding est transmise au délégué suivant dans le pipeline.

Configuration

Le code suivant utilise AddRequestDecompression(IServiceCollection) et UseRequestDecompression pour activer la décompression des requêtes pour les types Content-Encodingpar défaut :

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRequestDecompression();

var app = builder.Build();

app.UseRequestDecompression();

app.MapPost("/", (HttpRequest request) => Results.Stream(request.Body));

app.Run();

Fournisseurs de décompression par défaut

Les valeurs d’en-tête Content-Encoding que l’intergiciel de décompression de requêtes prend en charge par défaut sont répertoriées dans le tableau suivant :

Valeurs d’en-tête Content-Encoding Description
br Format de données compressées Brotli
deflate Format de données compressées DEFLATE
gzip Format de fichier Gzip

Fournisseurs de décompression personnalisée

Il est possible d’ajouter la prise en charge des encodages personnalisés en créant des classes de fournisseurs de décompression personnalisée qui implémentent IDecompressionProvider :

public class CustomDecompressionProvider : IDecompressionProvider
{
    public Stream GetDecompressionStream(Stream stream)
    {
        // Perform custom decompression logic here
        return stream;
    }
}

Les fournisseurs de décompression personnalisée sont inscrits avec RequestDecompressionOptions et leurs valeurs d’en-tête Content-Encoding correspondantes :

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRequestDecompression(options =>
{
    options.DecompressionProviders.Add("custom", new CustomDecompressionProvider());
});

var app = builder.Build();

app.UseRequestDecompression();

app.MapPost("/", (HttpRequest request) => Results.Stream(request.Body));

app.Run();

Limites de la taille des demandes

Afin de se protéger contre les bombes zip ou les bombes de décompression :

  • La taille maximale du corps de la requête décompressée est limitée à la limite de taille du corps de la demande appliquée par le point de terminaison ou le serveur.
  • Si le nombre d’octets lus à partir du flux de corps de requête décompressé dépasse la limite, une exception InvalidOperationException est levée pour empêcher la lecture d’octets supplémentaires à partir du flux.

Dans l’ordre de priorité, la taille maximale des requêtes pour un point de terminaison est définie par :

  1. IRequestSizeLimitMetadata.MaxRequestBodySize, comme RequestSizeLimitAttribute ou DisableRequestSizeLimitAttribute pour les points de terminaison MVC.
  2. Limite de taille IHttpMaxRequestBodySizeFeature.MaxRequestBodySize de serveur globale. MaxRequestBodySize peut être remplacé par requête avec IHttpMaxRequestBodySizeFeature.MaxRequestBodySize, mais la limite configurée par défaut pour l’implémentation du serveur web est définie par défaut.
Implémentation de serveur web Configuration MaxRequestBodySize
HTTP.sys HttpSysOptions.MaxRequestBodySize
IIS IISServerOptions.MaxRequestBodySize
Kestrel KestrelServerLimits.MaxRequestBodySize

Avertissement

La désactivation de la limite de taille du corps de la requête présente un risque de sécurité en ce qui concerne la consommation non contrôlée des ressources, en particulier si le corps de la demande est mis en mémoire tampon. Assurez-vous que des protections sont en place pour atténuer le risque d’attaques par déni de service (DoS).

Ressources supplémentaires