Распаковка запросов в ASP.NET Core

Автор: Дэвид Эйкер (David Acker)

ПО промежуточного слоя для распаковки запросов предоставляет такие преимущества:

  • позволяет конечным точкам API принимать запросы со сжатым содержимым;
  • использует заголовок HTTP Content-Encoding, чтобы автоматически обнаруживать и распаковывать запросы, содержащие сжатое содержимое;
  • устраняет необходимость писать код для обработки сжатых запросов.

Если значение заголовка Content-Encoding в запросе соответствует одному из доступных поставщиков распаковки, ПО промежуточного слоя:

  • использует этот поставщик для переноса HttpRequest.Body в подходящий поток распаковки;
  • удаляет заголовок Content-Encoding, так как текст запроса больше не сжат.

ПО промежуточного слоя для распаковки игнорирует запросы, не содержащие заголовок Content-Encoding.

Распаковка:

  • Происходит при чтении текста запроса. Это значит, что при привязке модели распаковка осуществляется в конечной точке. Текст запроса не декомпрессируется с нетерпением.
  • При попытке считывать декомпрессованный текст запроса с недопустимыми сжатыми данными для указанного Content-Encoding, создается исключение. Brotli может бросать System.InvalidOperationException: Decoder ran into invalid data. Deflate и GZip могут бросать System.IO.InvalidDataException: The archive entry was compressed using an unsupported compression method.

Если ПО промежуточного слоя обнаруживает запрос со сжатым содержимым, но его не удается распаковать, запрос передается следующему делегату в конвейере. Например, запрос со значением неподдерживаемого Content-Encoding заголовка или несколькими Content-Encoding значениями заголовков передается следующему делегату в конвейере.

Настройка

Следующий код использует AddRequestDecompression(IServiceCollection) и включает распаковку запроса для типов по умолчаниюContent-Encoding:UseRequestDecompression

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRequestDecompression();

var app = builder.Build();

app.UseRequestDecompression();

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

app.Run();

Поставщики распаковки по умолчанию

Значения заголовков Content-Encoding, которые по умолчанию поддерживает ПО промежуточного слоя распаковки запросов, перечислены в следующей таблице:

Значения заголовков Content-Encoding Description
br Формат сжатых данных Brotli
deflate Формат сжатых данных Deflate
gzip Формат файлов gzip

Настраиваемые поставщики распаковки

Поддержку пользовательских кодировок можно добавлять, создавая настраиваемые классы поставщиков распаковки, реализующие IDecompressionProvider:

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

Настраиваемые поставщики распаковки регистрируются с использованием RequestDecompressionOptions вместе с соответствующими значениями заголовков Content-Encoding:

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();

Предельный размер запросов

Для защиты от ZIP-, или распаковочных атак, принимаются следующие меры:

  • максимальный размер текста распакованного запроса ограничивается согласно лимиту на размер текста запроса в конечной точке или на сервере;
  • если из потока текста распаковываемого запроса считывается количество байт, превышающее ограничение, создается исключение InvalidOperationException, чтобы предотвратить чтение дополнительных байтов из потока.

Максимальный размер запроса для конечной точки задается в порядке приоритета следующим образом:

  1. IRequestSizeLimitMetadata.MaxRequestBodySize, например RequestSizeLimitAttribute или DisableRequestSizeLimitAttribute для конечных точек MVC.
  2. Глобальное серверное ограничение размера — IHttpMaxRequestBodySizeFeature.MaxRequestBodySize. MaxRequestBodySize можно переопределить для каждого запроса, используя свойство IHttpMaxRequestBodySizeFeature.MaxRequestBodySize, но по умолчанию применяется ограничение, настроенное для реализации веб-сервера.
Реализация веб-сервера MaxRequestBodySizeКонфигурация
HTTP.sys HttpSysOptions.MaxRequestBodySize
IIS IISServerOptions.MaxRequestBodySize
Kestrel KestrelServerLimits.MaxRequestBodySize

Предупреждение

Отключение лимита для размера текста запроса создает риск для безопасности, связанный с неконтролируемым потреблением ресурсов, особенно если текст запроса буферизуется. Убедитесь, что приняты меры по безопасности, чтобы снизить риск атак типа отказ в обслуживании (DoS).

Дополнительные ресурсы