Aspnetcore: Support the new "Forwarded" header (RFC 7239)

Created on 27 Jan 2016  路  16Comments  路  Source: dotnet/aspnetcore

There is now a standard for the most common X-Forwarded-* headers. It was introduced with RFC 7239: "Forwarded HTTP Extension".

Example: Forwarded: for=192.0.2.60;proto=http;by=203.0.113.43

It would be great if this could be supported.

affected-medium area-middleware enhancement severity-minor

Most helpful comment

"Are you aware of any proxies that actually set that new header?"

Arguably that point is somewhat circular, i.e. maybe if ASP.NET Core supported the 'Forwarded' header there would be more pressure on the reverse proxy implementations to support it. It is after all the only approach that actually has a formal specification (rfc7239).

All 16 comments

Yes, we've seen it. Are you aware of any proxies that actually set that new header?

No - but I haven't looked either. I recently built a small ASP.NET gateway proxy for Azure Service Fabric and that's why I stumbled upon this RFC. I guess this definitely isn't high priority since there won't be anyone who's setting just this header for a looong time. It would just be good to support it someday since it is a standard and will eventually get more common.

I have a scenario whereby we have a reverse proxy (internally) passing requests to backend api鈥檚 and web apps; and one of the api's is ASP.NET 5 and using the BasicMiddleware classes to handle the headers from the upstream proxies. The team had implemented the newer RFC so BasicMiddleware can't handle Forwarded headers from the RFC.

We're using Forwarded and plan to implement it in the proxies we use, such as NGINX. The header is becoming more mainstream and it would be good of Microsoft to advocate for its use over the (non-standard) X-Forwarded-* headers.

Would also like to have ability to extend the 'Forwared' header with a PathBase parameter as well as support for that with the current implementation i.e. X-Forwarded-PathBase

(somewhat) Related: https://github.com/aspnet/Hosting/issues/1120

@damianh do you expect PathBase to be different per request? That Hosting issue is about getting one value at startup.

Yes, I would certainly like to be able to do so on a per-request basis. This will allow two scenarios where generated URLs and paths (fully qualified, rooted, relative) would "just work":

  1. Re-configuring the proxy to a new path base (e.g. http://proxy/foo/ -> http://backend/ to http://proxy/bar/ -> http://backend/ ) without having to reconfigure and restart the backend server.

  2. Having one backend server responding on two separate paths (e.g. http://proxy/foo/ | http://proxy/bar/ -> http://backend/). Useful if "migrating" to a new route without breaking clients in situ.

@Tratcher This is what I use near top of my Configure(IApplicationBuilder app):

        var forwardedHeadersOptions = new ForwardedHeadersOptions
        {
            ForwardedHeaders = ForwardedHeaders.All
        };
        app.UseForwardedHeaders(forwardedHeadersOptions);
        app.Use((context, next) => {
            if (context.Request.Headers.TryGetValue("X-Forwarded-PathBase", out var pathBases))
            {
                context.Request.PathBase = pathBases.First();
            }
            return next();
        });

"Are you aware of any proxies that actually set that new header?"

Arguably that point is somewhat circular, i.e. maybe if ASP.NET Core supported the 'Forwarded' header there would be more pressure on the reverse proxy implementations to support it. It is after all the only approach that actually has a formal specification (rfc7239).

Would also like to have ability to extend the 'Forwared' header with a PathBase parameter as well as support for that with the current implementation i.e. X-Forwarded-PathBase

Just to mention that I've shipped a package that supports this https://github.com/ProxyKit/HttpOverrides

"Are you aware of any proxies that actually set that new header?"

Arguably that point is somewhat circular, i.e. maybe if ASP.NET Core supported the 'Forwarded' header there would be more pressure on the reverse proxy implementations to support it. It is after all the only approach that actually has a formal specification (rfc7239).

Indeed. If no one starts implementing the standard, it will never gain traction. Also: Spring has support for this Forwarded header since 2016...

Perhaps someone could reach out to the YARP team to get their views, i.e. e.g. are they planning to implement rfc7239

microsoft/reverse-proxy

Yes, we've seen it. Are you aware of any proxies that actually set that new header?

@Tratcher, it is the documented way for Azure APIM : https://docs.microsoft.com/en-us/azure/api-management/policies/set-header-to-enable-backend-to-construct-urls

Perhaps someone could reach out to the YARP team to get their views, i.e. e.g. are they planning to implement rfc7239

microsoft/reverse-proxy

YARP is being built by this team. We did add support for the new header in YARP but it's off by default. See https://microsoft.github.io/reverse-proxy/articles/transforms.html#forwarded

Design note: this probably should be implemented in AspNetCore as a whole new middleware, it takes very different options. I'm also not sure what to do with the randomized client ids, stash them in a new request feature?

Design note: this probably should be implemented in AspNetCore as a whole new middleware, it takes very different options.

@Tratcher I think there is value in keeping it in the same middleware, if possible, as the headers are conceptually the same. A class called ForwardedHeadersMiddleware is where I would expect to find the standards-compliant implementation, I wouldn't keep looking for a different middleware.

What if Forwarded was added to the ForwardedHeaders enum? To restrict the processing, in line with how X-Forwarded-* is configured, the enum could include ForwardedBy, ForwardedFor, ForwardedHost and ForwardedProto as well.

Support for both Forwarded and X-Forwarded-* could then be configured together, such as:

app.UseForwardedHeaders(new ForwardedHeadersOptions
{
    ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.ForwardedFor
});

There are some options that only make sense for the X-Forwarded-* headers, but is that a problem? They can either be ignored or cause an exception if they are set when only support for the Forwarded header is configured.

I'm also not sure what to do with the randomized client ids, stash them in a new request feature?

Would it be a plausible alternative to just provide a class for parsing the Forwarded header and leave the rest up to the developer when using randomized client ids?

Support for both Forwarded and X-Forwarded-* could then be configured together, such as:

app.UseForwardedHeaders(new ForwardedHeadersOptions
{
    ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.ForwardedFor
});

That's a good example of why these shouldn't be combine into one middleware. If a request has both headers then what order should they be processed in? It's ambiguous.

Was this page helpful?
0 / 5 - 0 ratings