Cloudflare je populární služba zajišťující (mimo jiné) CDN a reverzní proxy. To znamená, že se postaví mezi váš server a klienta a zařizuje různé zajímavé služby, od geografické dostupnosti přes zabezpečení po cacheování. Skrývá ale IP adresu klienta. Napsal jsem knihovnu, která umožňuje ASP.NET Core aplikaci transparentně zjistit IP adresu klienta, i když je publikována přes Cloudflare.

TL;DR: Knihovnu najdete na https://github.com/ridercz/Altairis.Services.Cloudflare a NuGet balíček se jmenuje Altairis.Services.Cloudflare.

Cloudflare a proxy

Reverzní proxy je server (nebo tedy zpravidla více serverů), které se postaví mezi webovou aplikaci (web server) a klienta (browser). Reverzní proxy může poskytovat různé zajímavé služby, například:

Skrytí IP adresy klienta

Protože se Cloudflare postaví mezi váš server a klienta, nemá server možnost přímo vidět klientovu IP adresu - pro něj je klientem proxy server Cloudflare. Naštěstí pro nás přidává do požadavku Cloudflare svoje HTTP hlavičky, které obsahují údaje o klientovi:

V ASP.NET Core lze IP adresu klienta zjistit tak, že se zeptáte na vlastnost HttpContext.Connection.RemoteIpAddress. Nicméně, pokud je ve hře proxy, dostanete adresu proxy, ne skutečného klienta.

Forwarded headers middleware

Proto Microsoft jako součást ASP.NET nabízí middleware, který umí přečíst shora uvedené hlavičky a vlastnost RemoteIpAddress podle ní nastavit.

Pokud máte obvyklý setup, kdy je vše na jednom serveru a web je publikován pomocí IIS, Nginxu nebo něčeho podobného, funguje to výborně bez nutnosti obsáhlejší konfigurace. Nicméně pokud používáte CDN službu, je to složitější. Forwarded Headers Middleware sice umí přečíst hlavičky typu X-Forwarded-For, ale je nutné pomocí vlastnosti KnownNetworks whitelistovat seznam podporovaných proxy. Děje se tak z dobrých, bezpečnostních důvodů. Pokud by totiž web byl náhodou najednou přístupný napřímo, kdokoliv by mohl hlavičku CF-Connecting-IP podvrhnout a podvrhout tak klientskou IP adresu.

Vypadá to pak v Program.cs nějak takhle:

builder.Services.Configure<ForwardedHeadersOptions>(options => {
    options.ForwardedHeaders = ForwardedHeaders.XForwardedFor;
    options.ForwardedForHeaderName = "CF-Connecting-IP";
    options.KnownNetworks.Add(new IPNetwork(IPAddress.Parse("10.0.0.0"), 24));
    options.KnownNetworks.Add(new IPNetwork(IPAddress.Parse("10.0.1.0"), 24));
});
var app = builder.Build();
app.UseForwardedHeaders();

Přičemž to KnownNetworks.Add musíme udělat pro všechny sítě, které Cloudflare používá. Jejich seznam je veřejně dostupný pro IPv4 i IPv6.

Altairis.Services.Cloudflare

Proto jsem napsal jednoduchou knihovnu, která si při startu aplikace stáhne z výše uvedených adres seznamy sítí a zkonfiguruje Forwarded Headers Middleware tak, aby správně fungoval s Cloudflare. Přidání podpory je pak směčně jednoduché.

Nejdříve musíte nainstalovat NuGet balíček:

Install-Package Altairis.Services.Cloudflare

Potom stačí v Program.cs zavolat:

app.UseCloudflare();

Knihovna se postará o všechno ostatní.

Zdrojové kódy najdete jako vždy na GitHubu a jsou dostupné zdarma pod MIT licencí.