asp.netsslwebformsowinowin-middleware

.NET Framework equivalent of IApplicationBuilder.UseForwardedHeaders()


I'm working with a ASP.NET WebForms application running on .NET Framework 4.7.2 which is sitting behind an Azure Application Gateway. The gateway performs SSL hand-off so is adding a X-Forwarded-Proto="https" header.

I also have a .NET Core API in which I can configure

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    app.UseForwardedHeaders();
    app.UseHsts();
    app. //...
}

This is documented here, but is specific to .NET Core.

I've been unable to find an equivalent of UseForwardedHeaders for .NET Framework - is there an equivalent?

Also, the WebForms application is running on OWIN, so I can do something like this, but I'm not sure how to complete it.

public void Configuration(IAppBuilder app)
{
    app.Use(async (context, next) =>
            {
                var forwardedProto = context.Request.Headers["X-Forwarded-Proto"];

                if (forwardedProto.ToLower() == "https")
                {
                    // what now?
                }

                await next();
            });
}

Is there an out-of-the-box solution for .NET Framework, or advice on how best to handle this?


Solution

  • I ended up building my own middleware.

    public static class UseForwardedHeadersExtension
    {
        private const string ForwardedHeadersAdded = "ForwardedHeadersAdded";
    
        /// <summary>
        /// Checks for the presence of <c>X-Forwarded-For</c> and <c>X-Forwarded-Proto</c> headers, and if present updates the properties of the request with those headers' details.
        /// </summary>
        /// <remarks>
        /// This extension method is needed for operating our website on an HTTP connection behind a proxy which handles SSL hand-off. Such a proxy adds the <c>X-Forwarded-For</c>
        /// and <c>X-Forwarded-Proto</c> headers to indicate the nature of the client's connection.
        /// </remarks>
        public static IAppBuilder UseForwardedHeaders(this IAppBuilder app)
        {
            if (app == null)
            {
                throw new ArgumentNullException(nameof(app));
            }
    
            // No need to add more than one instance of this middleware to the pipeline.
            if (!app.Properties.ContainsKey(ForwardedHeadersAdded))
            {
                app.Properties[ForwardedHeadersAdded] = true;
    
                app.Use(async (context, next) =>
                        {
                            var request = context.Request;
    
                            if (request.Scheme != Uri.UriSchemeHttps && String.Equals(request.Headers["X-Forwarded-Proto"], Uri.UriSchemeHttps, StringComparison.OrdinalIgnoreCase))
                            {
                                var httpContext = context.Get<HttpContextBase>(typeof(HttpContextBase).FullName);
                                var serverVars = httpContext.Request.ServerVariables;
                                serverVars["HTTPS"] = "on";
                                serverVars["SERVER_PORT_SECURE"] = "1";
                                serverVars["SERVER_PORT"] = "443";
                                serverVars["HTTP_HOST"] = request.Headers.ContainsKey("X-Forwarded-Host") ? request.Headers["X-Forwarded-Host"] : serverVars["HTTP_HOST"];
                            }
    
                            await next.Invoke().ConfigureAwait(false);
                        });
            }
    
            return app;
        }
    }