We still open tickets where every audit row shows 127.0.0.1 and password-reset mail ships http:// links for a site that only answers on HTTPS. IIS (or the load balancer in front of it) already finished TLS. The ASP.NET Core app never saw the original scheme or client address because forwarded headers were missing, incomplete, or registered too late.
That failure mode is loudest with ANCM out-of-process—Kestrel only talks to IIS on the loopback hop—and with any CDN or reverse proxy in front of the box. X-Forwarded-For and X-Forwarded-Proto are on the request; middleware that runs after UseHttpsRedirection, cookie auth, or your own absolute-URL helpers has already baked the wrong values into redirects, cookies, and logs.
#Register it before anything that reads scheme or IP
In a .NET 10 app, configure ForwardedHeadersOptions in DI and call UseForwardedHeaders at the top of the pipeline—before exception handling that logs RemoteIpAddress, before UseHttpsRedirection, before authentication. Limit the flags to what you actually consume. ForwardedHeaders.All is how people accidentally honor a forged Host.
builder.Services.Configure<ForwardedHeadersOptions>(options =>
{
options.ForwardedHeaders =
ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto;
// Out-of-process ANCM is loopback; add your LB CIDR when TLS dies one hop earlier.
// options.KnownProxies.Add(IPAddress.Parse("10.0.0.10"));
// options.KnownNetworks.Add(new IPNetwork(IPAddress.Parse("10.0.0.0"), 8));
});
var app = builder.Build();
app.UseForwardedHeaders();
// UseHttpsRedirection / UseAuthentication / MapControllers after this
#Trust the hop, not the internet
Default KnownProxies/KnownNetworks only trust loopback. That is enough when IIS and Kestrel share the machine and nothing sits in front. Clear those collections and reopen them to the world, and any client can spoof X-Forwarded-For. Don't do that. Name the load-balancer addresses you own; leave everything else rejected so a junk header cannot rewrite scheme or client IP.
After the next Web Deploy, hit one endpoint that logs Request.Scheme and Connection.RemoteIpAddress (or your request-id middleware). If you still see http and ::1 on a public HTTPS URL, the proxy is fine—the pipeline order or KnownProxies list is not. Fix that before you chase cookie Secure flags or redirect loops; they are usually symptoms of the same missing hop.
Comments
No comments yet