-
Notifications
You must be signed in to change notification settings - Fork 10.4k
Description
Is there an existing issue for this?
- I have searched the existing issues
Describe the bug
The request timeout feature relies on options, middleware, and attributes. If uses supply options or attributes, but forget the middleware, there's no indication that the timeouts aren't being applied.
Expected Behavior
Configuring timeouts on routes (or a default timeout policy ?) without adding the middleware should produce at least a runtime error rather than process the request without a timeout (dangerous). Note we also shouldn't short circuit endpoints with timeouts, we don't know what the short circuit logic is going to do.
An analyzer might help too.
We already have similar checks for auth, cors, and anti-forgery.
aspnetcore/src/Http/Routing/src/EndpointRoutingMiddleware.cs
Lines 161 to 178 in 997a1e8
if (!_routeOptions.SuppressCheckForUnhandledSecurityMetadata) | |
{ | |
if (endpoint.Metadata.GetMetadata<IAuthorizeData>() is not null) | |
{ | |
ThrowCannotShortCircuitAnAuthRouteException(endpoint); | |
} | |
if (endpoint.Metadata.GetMetadata<ICorsMetadata>() is not null) | |
{ | |
ThrowCannotShortCircuitACorsRouteException(endpoint); | |
} | |
if (endpoint.Metadata.GetMetadata<IAntiforgeryMetadata>() is { RequiresValidation: true } && | |
httpContext.Request.Method is {} method && | |
HttpExtensions.IsValidHttpMethodForForm(method)) | |
{ | |
ThrowCannotShortCircuitAnAntiforgeryRouteException(endpoint); | |
} |
aspnetcore/src/Http/Routing/src/EndpointMiddleware.cs
Lines 39 to 58 in 997a1e8
if (!_routeOptions.SuppressCheckForUnhandledSecurityMetadata) | |
{ | |
if (endpoint.Metadata.GetMetadata<IAuthorizeData>() is not null && | |
!httpContext.Items.ContainsKey(AuthorizationMiddlewareInvokedKey)) | |
{ | |
ThrowMissingAuthMiddlewareException(endpoint); | |
} | |
if (endpoint.Metadata.GetMetadata<ICorsMetadata>() is not null && | |
!httpContext.Items.ContainsKey(CorsMiddlewareInvokedKey)) | |
{ | |
ThrowMissingCorsMiddlewareException(endpoint); | |
} | |
if (endpoint.Metadata.GetMetadata<IAntiforgeryMetadata>() is { RequiresValidation: true } && | |
!httpContext.Items.ContainsKey(AntiforgeryMiddlewareWithEndpointInvokedKey)) | |
{ | |
ThrowMissingAntiforgeryMiddlewareException(endpoint); | |
} | |
} |
Found when consuming this feature in YARP, and mitigated there: dotnet/yarp#2307
Steps To Reproduce
using Microsoft.AspNetCore.Http.Timeouts;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRequestTimeouts();
var app = builder.Build();
// app.UseRequestTimeouts(); // Woops, forgot this, nothing works.
app.MapGet("/", async (HttpContext context) => {
try
{
await Task.Delay(TimeSpan.FromSeconds(10), context.RequestAborted);
}
catch (TaskCanceledException)
{
return Results.Content("Timeout!", "text/plain");
}
return Results.Content("No timeout!", "text/plain");
}).WithRequestTimeout(TimeSpan.FromSeconds(2));
// Returns "Timeout!"
app.MapGet("/attribute",
[RequestTimeout(milliseconds: 2000)] async (HttpContext context) => {
try
{
await Task.Delay(TimeSpan.FromSeconds(10), context.RequestAborted);
}
catch (TaskCanceledException)
{
return Results.Content("Timeout!", "text/plain");
}
return Results.Content("No timeout!", "text/plain");
});
// Returns "Timeout!"
app.Run();
Exceptions (if any)
None (but there should be).
.NET Version
.NET 8
Anything else?
This enforcement pattern isn't scalable/extensible. 3rd parties can't use the Endpoint/RoutingMiddleware to do their own enforcement for the presence of middleware. And for us, if we keep adding checks it's going to get messy. Could this be abstracted to a service? What happens if the user then forgets to add the service?