aspnetcore: Inconsistent URL decoding of HttpRequest.Path with percent-encoded characters
Describe the bug
HttpContext.Request.Path seems to decode percent-encoded URLs sometimes, but not all the time. The documentation says nothing about encoding. I expect it to never decode the path, but testing on ASP.NET Core 3.1 I get results like this:
| Request URL | context.Request.Path | Percent decoded? |
|---|---|---|
http://localhost:5000/test%24 |
/test$ |
Yes |
http://localhost:5000/test%24aa |
/test$aa |
Yes |
http://localhost:5000/test%25a |
/test%25a |
No |
http://localhost:5000/test%25aa |
/test%aa |
Yes |
http://localhost:5000/test%20aa |
/test%20aa |
No |
To Reproduce
Create an empty ASP.NET Core project and change the Startup class to
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.Use(async (context, next) =>
{
Console.WriteLine("Request path = " + context.Request.Path);
await context.Response.WriteAsync("Request path = " + context.Request.Path);
});
}
}
Program class unchanged from the template:
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) => Host.CreateDefaultBuilder(args).ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup<Startup>(); });
}
Then send the above GET requests to it from a web browser or curl.
Further technical details
- ASP.NET Core version: 3.1
dotnet --info:
dotnet --info
.NET SDK (reflecting any global.json):
Version: 5.0.200-preview.21079.7
Commit: 580b1c3770
Runtime Environment:
OS Name: Windows
OS Version: 6.1.7601
OS Platform: Windows
RID: win7-x64
Base Path: C:\Program Files\dotnet\sdk\5.0.200-preview.21079.7\
Host (useful for support):
Version: 5.0.3
Commit: c636bbdc8a
.NET SDKs installed:
3.0.100 [C:\Program Files\dotnet\sdk]
5.0.102 [C:\Program Files\dotnet\sdk]
5.0.103 [C:\Program Files\dotnet\sdk]
5.0.200-preview.21079.7 [C:\Program Files\dotnet\sdk]
.NET runtimes installed:
Microsoft.AspNetCore.All 2.1.25 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.All]
Microsoft.AspNetCore.App 2.1.25 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
Microsoft.AspNetCore.App 3.1.12 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
Microsoft.AspNetCore.App 5.0.3 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
Microsoft.NETCore.App 2.0.9 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.NETCore.App 2.1.25 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.NETCore.App 3.1.12 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.NETCore.App 5.0.3 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.WindowsDesktop.App 3.1.12 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
Microsoft.WindowsDesktop.App 5.0.3 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
- The IDE (VS / VS Code/ VS4Mac) you’re running on, and its version: VS 16.8.6
- OS: Windows 7 x64
About this issue
- Original URL
- State: open
- Created 3 years ago
- Comments: 19 (10 by maintainers)
@mbrenn this issue is specific to the path and %2F. Please open a new issue with the details for your query issue.
It is actually possible to get the raw original path with
httpContext.Features.Get<IHttpRequestFeature>()?.RawTarget(RawTarget). However this does also include the full query string, and as the docs say, the target may not always be a path (e.g. for server-wide OPTIONS requests).Examples from a Kestrel app:
http://localhost:5000/a/b%20c/a/b c/a/b%20c/a/b%20chttp://localhost:5000/a%2fb%20c/a%2fb c/a%2fb%20c/a%2fb%20chttp://localhost:5000/a%252fb%20c/a%2fb c/a%2fb%20c/a%252fb%20cEdit: you’d also need to be careful around dots in the path, as this can lead to path traversal attacks:
http://localhost:5000/a/./../.../.../.../a/./../...http://localhost:5000/a/%2e/.%2e/..%2e/.../.../a/%2e/.%2e/..%2e