azure-functions-host icon indicating copy to clipboard operation
azure-functions-host copied to clipboard

X-Forwarded-Host header missing in dotnet 8 isolated

Open paulverbeke opened this issue 1 year ago • 2 comments

The X-Forwarded-Host header provided by Azure Front Door is missing in a fresh new function in dotnet 8 isolated. Is working fine in dotnet 6 in-process but stops working when migrating to 8 isolated.

Investigative information

Please provide the following:

  • Timestamp:
  • Function App version: 4
  • Function App name:
  • Function name(s) (as appropriate):
  • Invocation ID:
  • Region: France Central

Repro steps

  1. create an Azure Function in dotnet 8 isolated
  2. in a function testforwardheader, output the value of the header X-Forwarded-Host req.Headers.TryGetValue("X-Forwarded-Host", out StringValues value)
  3. publish the function behind a Front Door with redirect rules to this app from the url subdomain.myfrontdoordomain.com/myfunction.
  4. call the function using subdomain.myfrontdoordomain.com/myfunction/api/testforwardheader

Expected behavior

in step 4 you should get the host requested by client, so subdomain.myfrontdoordomain.com

Actual behavior

in step 4 you get an empty string

Known workarounds

Someone found a workaround. They were able to find and restore the value from the bindingContext.BindingData using custom middleware.

Workaround
using Microsoft.AspNetCore.HttpOverrides;
using Microsoft.Azure.Functions.Worker;
using Microsoft.Azure.Functions.Worker.Middleware;
using Microsoft.Extensions.Hosting;
using Newtonsoft.Json;

var builder = new HostBuilder();

var host = builder
    .ConfigureFunctionsWebApplication(
        app =>
        {
            app.UseMiddleware<ForwardedForHeaderMiddleware>();
        })
    .Build();

await host.RunAsync();

public class ForwardedForHeaderMiddleware : IFunctionsWorkerMiddleware
{
    public async Task Invoke(FunctionContext context, FunctionExecutionDelegate next)
    {
        await CorrectForwardedForAsync(context);

        await next(context);
    }

    private static async Task CorrectForwardedForAsync(FunctionContext context)
    {
        var val = GetForwardedFor(context);
        var req = await context.GetHttpRequestDataAsync();
        req?.Headers.TryAddWithoutValidation(ForwardedHeadersDefaults.XForwardedForHeaderName, val);
    }

    private static string? GetForwardedFor(FunctionContext context)
    {
        var hdr = context.BindingContext.BindingData["Headers"];
        dynamic obj = JsonConvert.DeserializeObject(hdr.ToString());

        var val = obj[ForwardedHeadersDefaults.XForwardedForHeaderName]?.Value as string;
        return val;
    }
}

Related information

written in C#

Someone else had this problem

I know that the Front Door will send X-Forwarded-Host and X-Forwarded-Proto which we were able to use with the older Swashbuckle library which we used for In-Process Function Apps.

paulverbeke avatar Jun 27 '24 16:06 paulverbeke

@paulverbeke are you using the ASP.NET Core integration for your tests? In the HTTP proxying mode, all headers should be forwarded and will be processed by the worker.

fabiocav avatar Jun 28 '24 23:06 fabiocav

@fabiocav thanks for getting back quickly. Yes we are using ASP.NET Core integration. But I couldn't find anything online regarding "HTTP proxying mode". Is there something I need to enable or specify somewhere ?

EDIT: I just tested the starting Azure Functions template without ASP.NET Core integration (with HttpRequestData/HttpResponseData) and the header is available. Is it expected behavior that ASP.NET Core integration is causing header to be dropped ? If so why the default Visual Studio template is showing an example function with ASP.NET Core integration without this drawback be documented somewhere ?

paulverbeke avatar Jul 01 '24 08:07 paulverbeke

@fabiocav are there any updates on this? I'm also experiencing the same issue

trevonmckay avatar Nov 28 '24 03:11 trevonmckay

I'm also encountering this issue with my migration from .net 6 in process to .net isolated.

calloncampbell avatar Dec 03 '24 01:12 calloncampbell

I'm encountering the same issue. It looks like it does not matter who is providing the X-Forwarded-For header. Also the X-Forwarded-Host header is also affected.

That's unexpected and undocumented, breaking change.

@fabiocav Any news on this? It's unclear from this issue if this is a bug or a undocumented change. Any update appreciated.

Axes4-MarionFrei avatar Jan 07 '25 14:01 Axes4-MarionFrei

It seems that the X-Forwarded-* headers are being removed because ForwardedHeadersMiddleware is executed inside .ConfigureFunctionsWebApplication().

.ConfigureFunctionsWebApplication() Image

If this behavior is not desired, it might be possible to work around it by doing the following:

var builder = new HostBuilder();
builder
    .ConfigureFunctionsWebApplication(static builder =>
    {
        // add these lines
        builder.Services.PostConfigure<ForwardedHeadersOptions>(static o =>
        {
            o.ForwardLimit = 0;
            o.ForwardedHeaders = ForwardedHeaders.None;
        });
    });

var host = builder.Build();
host.Run();

However, please be aware that disabling the processing of X-Forwarded-* may have side effects, so it’s best to use this approach with careful consideration.

xin9le avatar Aug 15 '25 03:08 xin9le

However, please be aware that disabling the processing of X-Forwarded-* may have side effects, so it’s best to use this approach with careful consideration.

I tried this workaround for an Azure Function as the X-Forwarded headers are missing sometimes for me (not always - just for some requests!). Anyhow, unfortunately, this had a side-effect of breaking my Easy Auth login routines because it impacted the request Url (changing it to a localhost address instead of the custom domain).

// Redirect the user to the Easy Auth login url if they're not authenticated
var baseUrl = $"{req.Url.Scheme}://{req.Url.Authority}";
var loginUrl = $"{baseUrl}/.auth/login/aad?post_login_redirect_url={Uri.EscapeDataString(returnUrl)}";
...

Just wanted to warn anyone else of the possible side-effects.

TheObliterator avatar Aug 18 '25 23:08 TheObliterator