Closed brad-technologik closed 1 month ago
Upon further investigation, it seems like this is not specific OpaqueRedirection, as this occurs even with streaming disabled. In the reproduction steps, change Weather.razor
to disable streaming (@attribute [StreamRendering(false)]
and try again. When inspecting dev tools, you'll still see the Location
header of the page use http
instead of https
.
I've created a simple middleware workaround that changes the redirect (Location
header) to https if the original request was https scheme:
// Workaround for https://github.com/dotnet/aspnetcore/issues/57650.
app.Use(async (context, next) =>
{
await next(context);
if (context.Response.StatusCode == (int)HttpStatusCode.Redirect &&
context.Request.IsHttps && context.Response.Headers.Location.Count > 0)
{
var locations = context.Response.Headers.Location.ToArray();
for(int i=0; i<locations.Length; i++)
{
if (locations[i]!.StartsWith("http://"))
{
locations[i] = locations[i]!.Replace("http://", "https://");
}
}
context.Response.Headers["Location"] = new StringValues(locations);
}
});
@brad-technologik thanks for contacting us.
This seems to be an issue on your specific setup. Is the scheme on the incoming request that triggers the redirect HTTPS?
It is very unlikely that this is caused by opaque redirect as opposed to a misconfiguration on your app side. Opaque Redirect is a very thin wrapper over response.Redirect
and that simply uses whatever is available on HttpContext.
I would suggest you log the scheme that you add custom middleware on your environment to detect and log the scheme of the incoming request that triggers the opaque redirection. It's very likely that it is not set as HTTPS and that's the source of the issue.
@javiercn I think the bug lies in UseForwardedHeaders
middleware.
In my repro, when I add logging, X-Forwarded-Proto
is set to https
, but context.Request.IsHttps
is still false in downstream middleware:
api-1 | Referer:https://localhost/weather?
api-1 | Upgrade-Insecure-Requests:1
api-1 | X-Real-IP:192.168.65.1
api-1 | X-Forwarded-For:192.168.65.1
api-1 | X-Forwarded-Proto:https
api-1 | X-Forwarded-Host:my-site
api-1 | sec-ch-ua:"Chromium";v="128", "Not;A=Brand";v="24", "Google Chrome";v="128"
api-1 | sec-ch-ua-mobile:?0
api-1 | sec-ch-ua-platform:"macOS"
api-1 | Sec-Fetch-Site:same-origin
api-1 | Sec-Fetch-Mode:navigate
api-1 | Sec-Fetch-User:?1
api-1 | Sec-Fetch-Dest:document
api-1 | context.Request.IsHttps: False
When I add the following middleware, the redirects work as expected:
app.Use((context, next) =>
{
if (context.Request.Headers["X-Forwarded-Proto"]=="https")
context.Request.Scheme = "https";
return next(context);
});
However, I assumed that UseForwardedHeaders
was supposed to do what the above does. Did I use UseForwardedHeaders
incorrectly?
Changing
builder.Services.Configure<ForwardedHeadersOptions>(options =>
{
options.ForwardedHeaders =
ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto;
});
To
builder.Services.Configure<ForwardedHeadersOptions>(options =>
{
options.ForwardedHeaders = ForwardedHeaders.XForwardedProto;
});
fixed the issue, but I'm unclear why that worked, especially since that former is the example given in the documentation.
@brad-technologik thanks for the additional details.
I'm not sure what can be going on. The logic for it is https://github.com/dotnet/aspnetcore/blob/2152f3ba4b7b7618b9b6f1065eb65711311bdf42/src/Middleware/HttpOverrides/src/ForwardedHeadersMiddleware.cs#L120
I'm not sure if it's a bug on the code or a bug in the docs.
Can you include the trace-level ASP.NET Core logs from the ForwardedHeadersMiddleware
?
You might be running into an issue because the middleware verifies that the client claiming to be the proxy has the expected remote IP address as noted in the doc's troubleshooting section.
The request's original remote IP must match an entry in the
KnownProxies
orKnownNetworks
lists before forwarded headers are processed. This limits header spoofing by not accepting forwarders from untrusted proxies. When an unknown proxy is detected, logging indicates the address of the proxy:dbug: Microsoft.AspNetCore.HttpOverrides.ForwardedHeadersMiddleware[1] Unknown proxy: [::ffff:10.0.0.100]:54321
By default, KnownProxies
and KnownNetworks
only contain [::1]
and 127.0.0.0/8
respectively. I'm a little surprised that this only gets checked when ForwardedHeaders.XForwardedFor
is selected and not ForwardedHeaders.XForwardedProto
, but being able to spoof the scheme does seem like less of a security risk than being able to spoof a remote IP address.
If you know the IP address or subnet of the reverse proxy, I recommend adding it to KnownProxies
or KnownNetworks
. Otherwise, you can clear both lists to skip the check, but you need to beware that any client that can open a connection to your backend server will be able to spoof their IP address.
Another option is to set the ASPNETCORE_FORWARDEDHEADERS_ENABLED
environment variable to true or otherwise set the "ForwardedHeaders_Enabled" IConfiguration
to true.
To forward the scheme from the proxy in non-IIS scenarios, enable the Forwarded Headers Middleware by setting
ASPNETCORE_FORWARDEDHEADERS_ENABLED
totrue
. Warning: This flag uses settings designed for cloud environments and doesn't enable features such as theKnownProxies option
to restrict which IPs forwarders are accepted from.
If you do this, you will no longer need to call Configure<ForwardedHeadersOptions>(...
or app.UseForwardedHeaders();
yourself. WebApplicationBuilder
will set that up for you when it sees the "ForwardedHeaders_Enabled" config.
Hi @brad-technologik. We have added the "Needs: Author Feedback" label to this issue, which indicates that we have an open question for you before we can take further action. This issue will be closed automatically in 7 days if we do not hear back from you by then - please feel free to re-open it if you come back to this issue after that time.
This issue has been automatically marked as stale because it has been marked as requiring author feedback but has not had any activity for 4 days. It will be closed if no further activity occurs within 3 days of this comment. If it is closed, feel free to comment when you are able to provide the additional information and we will re-investigate.
See our Issue Management Policies for more information.
Is there an existing issue for this?
Describe the bug
I run my blazor hybrid app behind a load balancer. However, this causes
NavigationManager.NavigateTo
to break, since it tries to redirect to anHTTP
scheme when my app is accessed throughHTTPS
. Even after following instructions at Configure ASP.NET Core to work with proxy servers and load balancers, the http scheme is still not respected.During redirection, the browser emits an error and does not redirect:
Refreshing the page redirect correctly since it doesn't use OpaqueRedirection.
Expected Behavior
The opaque redirector should honor the HTTPS/HTTPS scheme based on forwarded headers from a load balancer.
Steps To Reproduce
Clone my repo here: https://github.com/TrieBr/redirect-bug
Enter 'password' for all 3 prompts.
Enter 'password'.
Enter 'password'.
CD back into the root folder (
cd ../
), and rundocker-compose up
.visit
https://localhost
on your browser.Open developer tools.
Then click "Weather" on the left navigation.
Observe in the "network" tab, the fetch of something like
https://localhost/_framework/opaque-redirect?url=...
Observe that the returned header
Location
uses http and nothttps
.On localhost, this isn't an issue, but on a real domain, the browser will throw an error:
This request has been blocked; the content must be served over HTTPS
The returned
Location
header should use the same http scheme in the request, honoring load balancer forwarded schemes.Exceptions (if any)
No response
.NET Version
8.0.100
Anything else?
.NET SDK: Version: 8.0.100 Commit: 57efcf1350 Workload version: 8.0.100-manifests.a7f084b6
Runtime Environment: OS Name: Mac OS X OS Version: 14.5 OS Platform: Darwin RID: osx-arm64 Base Path: /usr/local/share/dotnet/sdk/8.0.100/
.NET workloads installed: Workload version: 8.0.100-manifests.a7f084b6 [wasm-tools] Installation Source: SDK 8.0.100 Manifest Version: 8.0.3/8.0.100 Manifest Path: /usr/local/share/dotnet/sdk-manifests/8.0.100/microsoft.net.workload.mono.toolchain.current/8.0.3/WorkloadManifest.json Install Type: FileBased
Host: Version: 8.0.4 Architecture: arm64 Commit: 2d7eea2529
.NET SDKs installed: 6.0.201 [/usr/local/share/dotnet/sdk] 6.0.402 [/usr/local/share/dotnet/sdk] 6.0.404 [/usr/local/share/dotnet/sdk] 7.0.100 [/usr/local/share/dotnet/sdk] 7.0.101 [/usr/local/share/dotnet/sdk] 7.0.302 [/usr/local/share/dotnet/sdk] 8.0.100-rc.1.23463.5 [/usr/local/share/dotnet/sdk] 8.0.100-rc.2.23502.2 [/usr/local/share/dotnet/sdk] 8.0.100 [/usr/local/share/dotnet/sdk]
.NET runtimes installed: Microsoft.AspNetCore.App 6.0.3 [/usr/local/share/dotnet/shared/Microsoft.AspNetCore.App] Microsoft.AspNetCore.App 6.0.10 [/usr/local/share/dotnet/shared/Microsoft.AspNetCore.App] Microsoft.AspNetCore.App 6.0.12 [/usr/local/share/dotnet/shared/Microsoft.AspNetCore.App] Microsoft.AspNetCore.App 7.0.0 [/usr/local/share/dotnet/shared/Microsoft.AspNetCore.App] Microsoft.AspNetCore.App 7.0.1 [/usr/local/share/dotnet/shared/Microsoft.AspNetCore.App] Microsoft.AspNetCore.App 7.0.5 [/usr/local/share/dotnet/shared/Microsoft.AspNetCore.App] Microsoft.AspNetCore.App 8.0.0-rc.1.23421.29 [/usr/local/share/dotnet/shared/Microsoft.AspNetCore.App] Microsoft.AspNetCore.App 8.0.0-rc.2.23480.2 [/usr/local/share/dotnet/shared/Microsoft.AspNetCore.App] Microsoft.AspNetCore.App 8.0.0 [/usr/local/share/dotnet/shared/Microsoft.AspNetCore.App] Microsoft.NETCore.App 6.0.3 [/usr/local/share/dotnet/shared/Microsoft.NETCore.App] Microsoft.NETCore.App 6.0.10 [/usr/local/share/dotnet/shared/Microsoft.NETCore.App] Microsoft.NETCore.App 6.0.12 [/usr/local/share/dotnet/shared/Microsoft.NETCore.App] Microsoft.NETCore.App 7.0.0 [/usr/local/share/dotnet/shared/Microsoft.NETCore.App] Microsoft.NETCore.App 7.0.1 [/usr/local/share/dotnet/shared/Microsoft.NETCore.App] Microsoft.NETCore.App 7.0.5 [/usr/local/share/dotnet/shared/Microsoft.NETCore.App] Microsoft.NETCore.App 8.0.0-rc.1.23419.4 [/usr/local/share/dotnet/shared/Microsoft.NETCore.App] Microsoft.NETCore.App 8.0.0-rc.2.23479.6 [/usr/local/share/dotnet/shared/Microsoft.NETCore.App] Microsoft.NETCore.App 8.0.0 [/usr/local/share/dotnet/shared/Microsoft.NETCore.App] Microsoft.NETCore.App 8.0.4 [/usr/local/share/dotnet/shared/Microsoft.NETCore.App]
Other architectures found: x64 [/usr/local/share/dotnet/x64]
Environment variables: Not set
global.json file: Not found
Learn more: https://aka.ms/dotnet/info
Download .NET: https://aka.ms/dotnet/download