Konfigurasikan ASP.NET Core agar berfungsi dengan server proksi dan penyeimbang beban

Catatan

Ini bukan versi terbaru dari artikel ini. Untuk rilis saat ini, lihat versi .NET 10 dari artikel ini.

Peringatan

Versi ASP.NET Core ini tidak lagi didukung. Untuk informasi selengkapnya, lihat Kebijakan Dukungan .NET dan .NET Core. Untuk rilis saat ini, lihat versi .NET 10 dari artikel ini.

Oleh Chris Ross

Dalam konfigurasi yang direkomendasikan untuk ASP.NET Core, aplikasi dihosting menggunakan ASP.NET Core Module (ANCM) untuk IIS, Nginx, atau Apache. Proxy server, load balancer, dan perangkat jaringan lainnya sering mengaburkan informasi tentang permintaan sebelum mencapai aplikasi.

  • Ketika permintaan HTTPS diproksi melalui HTTP, skema asli (HTTPS) hilang dan harus diteruskan di header.
  • Karena aplikasi menerima permintaan dari proksi dan bukan sumber sebenarnya di Internet atau jaringan perusahaan, alamat IP klien asal juga harus diteruskan di header.

Informasi ini mungkin penting dalam pemrosesan permintaan, misalnya dalam pengalihan, autentikasi, pembuatan tautan, evaluasi kebijakan, dan geolokasi klien.

Aplikasi yang dimaksudkan untuk dijalankan di farm web sebaiknya merujuk ke Host ASP.NET Core di farm web.

Header yang diteruskan

Menurut konvensi, proksi meneruskan informasi di header HTTP.

Kepala Halaman Deskripsi
X-Forwarded-For (XFF) Menyimpan informasi tentang klien yang memulai permintaan dan proksi berikutnya dalam rantai proksi. Parameter ini mungkin berisi alamat IP dan, secara opsional, nomor port. Dalam rantai server proksi, parameter pertama menunjukkan klien tempat permintaan pertama kali dibuat. Pengidentifikasi proksi berikutnya mengikuti. Proksi terakhir dalam rantai tidak ada dalam daftar parameter. Alamat IP proksi terakhir, dan secara opsional nomor port, tersedia sebagai alamat IP jarak jauh di lapisan transportasi.
X-Forwarded-Proto (XFP) Nilai skema asal, HTTP atau HTTPS. Nilai mungkin juga merupakan daftar skema jika permintaan telah melintasi beberapa proksi.
X-Forwarded-Host (XFH) Nilai asli bidang header Host. Biasanya, proksi tidak mengubah header Host. Lihat Microsoft Security Advisory CVE-2018-0787 untuk informasi tentang kerentanan elevasi hak istimewa yang memengaruhi sistem di mana proksi tidak memvalidasi atau membatasi header Host ke nilai yang diketahui baik.
X-Forwarded-Prefix Jalur dasar asli yang diminta oleh klien. Header ini dapat berguna bagi aplikasi untuk menghasilkan URL, pengalihan, atau tautan dengan benar kembali ke klien.

Middleware Forwarded Headers, ForwardedHeadersMiddleware, membaca header ini dan mengisi bidang terkait pada HttpContext.

Pembaruan middleware:

Untuk informasi selengkapnya tentang sebelumnya, lihat masalah GitHub ini.

Pengaturan default Middleware Header yang Diteruskan dapat dikonfigurasi. Untuk pengaturan default:

  • Hanya ada satu proksi antara aplikasi dan sumber permintaan.
  • Hanya alamat loopback yang dikonfigurasi untuk proksi yang diketahui dan jaringan yang diketahui.
  • Header yang diteruskan diberi nama X-Forwarded-For, , X-Forwarded-ProtoX-Forwarded-Host dan X-Forwarded-Prefix.
  • Nilai ForwardedHeaders adalah ForwardedHeaders.None. Pengirim yang diinginkan harus diatur di sini untuk mengaktifkan middleware.

Tidak semua perangkat jaringan secara otomatis menambahkan header X-Forwarded-For dan X-Forwarded-Proto tanpa konfigurasi tambahan. Lihat panduan produsen perangkat Anda jika permintaan terproksi tidak berisi header ini ketika mencapai aplikasi. Jika perangkat menggunakan nama header yang berbeda dari X-Forwarded-For dan X-Forwarded-Proto, atur opsi ForwardedForHeaderName dan ForwardedProtoHeaderName agar sesuai dengan nama header yang digunakan oleh perangkat. Untuk informasi selengkapnya, lihat Opsi Middleware Header yang Diteruskan dan Konfigurasi untuk proksi yang menggunakan nama header yang berbeda.

Modul IIS/IIS Express dan ASP.NET Core

IIS Integration Middleware mengaktifkan Forwarded Headers Middleware secara default saat aplikasi dihosting out-of-process di belakang IIS dan ASP.NET Core Module (ANCM) untuk IIS. Middleware Header yang Diteruskan diaktifkan untuk dijalankan terlebih dahulu di alur middleware dengan konfigurasi terbatas khusus untuk Modul ASP.NET Core. Konfigurasi terbatas karena isu kepercayaan terhadap header yang diteruskan, misalnya, IP spoofing. Middleware dikonfigurasi untuk meneruskan header X-Forwarded-For dan X-Forwarded-Proto serta dibatasi hanya pada satu proxy localhost. Jika konfigurasi tambahan diperlukan, lihat opsi Middleware Header yang Diteruskan.

Skenario server proksi dan load balancer lainnya

Di luar penggunaan Integrasi IIS saat menghosting secara di luar proses, Middleware Header yang Diteruskan tidak diaktifkan secara default. Middleware "Forwarded Headers" harus diaktifkan agar aplikasi memproses header yang diteruskan dengan UseForwardedHeaders. Setelah mengaktifkan middleware, jika tidak ada ForwardedHeadersOptions yang ditentukan ke middleware, ForwardedHeadersOptions.ForwardedHeaders default adalah ForwardedHeaders.None.

Konfigurasikan middleware dengan ForwardedHeadersOptions untuk meneruskan X-Forwarded-For header dan X-Forwarded-Proto .

Urutan Middleware Header yang Diteruskan

Middleware Pengalihan Header harus dijalankan sebelum middleware lainnya. Urutan ini memastikan bahwa middleware yang mengandalkan informasi header yang diteruskan dapat memanfaatkan data header untuk pemrosesan. Middleware Penerusan Header dapat berjalan setelah proses diagnostik dan penanganan kesalahan, tetapi harus dijalankan terlebih dahulu sebelum memanggil UseHsts.

using Microsoft.AspNetCore.HttpOverrides;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.Configure<ForwardedHeadersOptions>(options =>
{
    options.ForwardedHeaders =
        ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto;
});

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseForwardedHeaders();
    app.UseHsts();
}
else
{
    app.UseDeveloperExceptionPage();
    app.UseForwardedHeaders();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseAuthorization();

app.MapRazorPages();

app.Run();

Atau, panggil UseForwardedHeaders sebelum diagnostik:

using Microsoft.AspNetCore.HttpOverrides;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.Configure<ForwardedHeadersOptions>(options =>
{
    options.ForwardedHeaders =
        ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto;
});

var app = builder.Build();

app.UseForwardedHeaders();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseAuthorization();

app.MapRazorPages();

app.Run();

Catatan

Jika tidak ada ForwardedHeadersOptions yang ditentukan atau diterapkan langsung ke metode ekstensi dengan UseForwardedHeaders, header default yang akan diteruskan adalah ForwardedHeaders.None. Properti ForwardedHeaders harus dikonfigurasi dengan header untuk diteruskan.

Konfigurasi Nginx

Untuk meneruskan X-Forwarded-For header dan X-Forwarded-Proto , lihat Host ASP.NET Core di Linux dengan Nginx.

Konfigurasi Apache

X-Forwarded-For ditambahkan secara otomatis. Untuk informasi selengkapnya, lihat Modul Apache mod_proxy: Header Permintaan Proksi Terbalik.

Opsi Middleware Header yang Diteruskan

ForwardedHeadersOptions mengontrol perilaku Forwarded Headers Middleware. Contoh berikut mengubah nilai default:

  • Membatasi jumlah entri dalam header yang diteruskan ke 2.
  • Menambahkan alamat proksi yang diketahui dari 127.0.10.1.
  • Mengubah nama header yang diteruskan dari default X-Forwarded-For ke X-Forwarded-For-My-Custom-Header-Name.
using System.Net;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.Configure<ForwardedHeadersOptions>(options =>
{
    options.ForwardLimit = 2;
    options.KnownProxies.Add(IPAddress.Parse("127.0.10.1"));
    options.ForwardedForHeaderName = "X-Forwarded-For-My-Custom-Header-Name";
});

var app = builder.Build();

app.UseForwardedHeaders();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseAuthorization();

app.MapRazorPages();

app.Run();
Opsi Deskripsi
AllowedHosts Membatasi host berdasarkan header X-Forwarded-Host ke nilai yang disediakan.
  • Nilai dibandingkan menggunakan ordinal-ignore-case.
  • Nomor port harus dikecualikan.
  • Jika daftar kosong, semua host diizinkan.
  • Kartu wildcard * tingkat atas memungkinkan semua host yang tidak kosong.
  • Wildcard subdomain diizinkan tetapi tidak cocok dengan domain akar. Misalnya, *.contoso.com cocok dengan subdomain foo.contoso.com tetapi bukan domain contoso.comakar .
  • Nama host Unicode diizinkan tetapi dikonversi ke Punycode untuk pencocokan.
  • Alamat IPv6 harus menyertakan tanda kurung batas dan berada dalam bentuk konvensional (misalnya, [ABCD:EF01:2345:6789:ABCD:EF01:2345:6789]). Alamat IPv6 tidak ditangani secara khusus untuk memeriksa kesetaraan logis antara format yang berbeda, dan tidak ada kanonisasi yang dilakukan.
  • Kegagalan untuk membatasi host yang diizinkan mungkin memungkinkan cyberattacker untuk memalsukan tautan yang dihasilkan oleh layanan.
Nilai defaultnya adalah kosong IList<string>.
ForwardedForHeaderName Gunakan header yang ditentukan oleh properti ini alih-alih yang ditentukan oleh ForwardedHeadersDefaults.XForwardedForHeaderName. Opsi ini digunakan ketika proksi/penerus tidak menggunakan X-Forwarded-For header tetapi menggunakan beberapa header lain untuk meneruskan informasi.

Default adalah X-Forwarded-For.
ForwardedHeaders Mengidentifikasi penerus mana yang harus diproses. Lihat ForwardedHeaders Enum untuk daftar bidang yang berlaku. Nilai umum yang ditetapkan ke properti ini adalah ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto.

Nilai defaultnya adalah ForwardedHeaders.None.
ForwardedHostHeaderName Gunakan header yang ditentukan oleh properti ini alih-alih yang ditentukan oleh ForwardedHeadersDefaults.XForwardedHostHeaderName. Opsi ini digunakan ketika proksi/penerus tidak menggunakan X-Forwarded-Host header tetapi menggunakan beberapa header lain untuk meneruskan informasi.

Default adalah X-Forwarded-Host.
ForwardedProtoHeaderName Gunakan header yang ditentukan oleh properti ini alih-alih yang ditentukan oleh ForwardedHeadersDefaults.XForwardedProtoHeaderName. Opsi ini digunakan ketika proksi/penerus tidak menggunakan X-Forwarded-Proto header tetapi menggunakan beberapa header lain untuk meneruskan informasi.

Default adalah X-Forwarded-Proto.
ForwardLimit Membatasi jumlah entri dalam header yang diproses. Atur ke null untuk menonaktifkan batas, tetapi ini hanya boleh dilakukan jika KnownProxies atau KnownNetworks dikonfigurasi. Mengatur nilai selainnull adalah tindakan pencegahan (tetapi bukan jaminan) untuk melindungi dari proksi yang salah dikonfigurasi dan permintaan berbahaya yang tiba dari saluran samping di jaringan.

Middleware Header yang diteruskan memproses header dalam urutan terbalik dari kanan ke kiri. Jika nilai default (1) digunakan, hanya nilai paling kanan dari header yang diproses kecuali nilai ForwardLimit ditingkatkan.

Default adalah 1.
KnownNetworks Rentang alamat jaringan yang diketahui untuk menerima header yang diteruskan. Berikan rentang IP menggunakan notasi Classless Interdomain Routing (CIDR).

Jika server menggunakan soket mode ganda, alamat IPv4 disediakan dalam format IPv6 (misalnya, 10.0.0.1 dalam IPv4 yang diwakili dalam IPv6 sebagai ::ffff:10.0.0.1). Lihat IPAddress.MapToIPv6. Tentukan apakah format ini diperlukan dengan melihat HttpContext.Connection.RemoteIpAddress.

Defaultnya adalah IList<IPNetwork> yang berisi satu entri untuk new IPNetwork(IPAddress.Loopback, 8).
KnownProxies Alamat proksi yang diketahui untuk menerima header yang diteruskan. Gunakan KnownProxies untuk menentukan kecocokan alamat IP yang tepat.

Jika server menggunakan soket mode ganda, alamat IPv4 disediakan dalam format IPv6 (misalnya, 10.0.0.1 dalam IPv4 yang diwakili dalam IPv6 sebagai ::ffff:10.0.0.1). Lihat IPAddress.MapToIPv6. Tentukan apakah format ini diperlukan dengan melihat HttpContext.Connection.RemoteIpAddress.

Defaultnya adalah IList<IPAddress> yang berisi satu entri untuk IPAddress.IPv6Loopback.
OriginalForHeaderName Gunakan header yang ditentukan oleh properti ini alih-alih yang ditentukan oleh ForwardedHeadersDefaults.XOriginalForHeaderName.

Default adalah X-Original-For.
OriginalHostHeaderName Gunakan header yang ditentukan oleh properti ini alih-alih yang ditentukan oleh ForwardedHeadersDefaults.XOriginalHostHeaderName.

Default adalah X-Original-Host.
OriginalProtoHeaderName Gunakan header yang ditentukan oleh properti ini alih-alih yang ditentukan oleh ForwardedHeadersDefaults.XOriginalProtoHeaderName.

Default adalah X-Original-Proto.
RequireHeaderSymmetry Mengharuskan jumlah nilai header selaras dengan ForwardedHeadersOptions.ForwardedHeaders yang sedang diproses.

Default dalam ASP.NET Core 1.x adalah true. Default dalam ASP.NET Core 2.0 atau yang lebih baru adalah false.

Skenario dan kasus penggunaan

Ketika tidak dimungkinkan untuk menambahkan header yang diteruskan serta semua permintaan telah aman

Dalam beberapa kasus, mungkin tidak mungkin untuk menambahkan header yang diteruskan ke permintaan yang diproksikan ke aplikasi. Jika proksi memberlakukan bahwa semua permintaan eksternal publik adalah HTTPS, skema dapat diatur secara manual sebelum menggunakan semua jenis middleware:

using Microsoft.AspNetCore.HttpOverrides;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.Configure<ForwardedHeadersOptions>(options =>
{
    options.ForwardedHeaders =
        ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto;
});

var app = builder.Build();

app.Use((context, next) =>
{
    context.Request.Scheme = "https";
    return next(context);
});

app.UseForwardedHeaders();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseAuthorization();

app.MapRazorPages();

app.Run();

Kode ini dapat dinonaktifkan dengan variabel lingkungan atau pengaturan konfigurasi lainnya dalam lingkungan pengembangan atau penahapan:

using Microsoft.AspNetCore.HttpOverrides;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.Configure<ForwardedHeadersOptions>(options =>
{
    options.ForwardedHeaders =
        ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto;
});

var app = builder.Build();

if (!app.Environment.IsProduction())
{
    app.Use((context, next) =>
    {
        context.Request.Scheme = "https";
        return next(context);
    });
}

app.UseForwardedHeaders();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseAuthorization();

app.MapRazorPages();

app.Run();

Bekerja dengan basis jalur dan proksi yang mengubah jalur permintaan

Beberapa proxy melewati path secara utuh tetapi dengan path dasar aplikasi yang harus dihapus supaya perutean berfungsi dengan baik. Middleware UsePathBaseExtensions.UsePathBase membagi jalur menjadi HttpRequest.Path dan jalur dasar aplikasi ke HttpRequest.PathBase.

Jika /foo adalah jalur dasar aplikasi untuk jalur proksi yang diteruskan sebagai /foo/api/1, middleware mengatur Request.PathBase ke /foo dan Request.Path ke /api/1 dengan perintah berikut:

app.UsePathBase("/foo");
// ...
app.UseRouting();

Catatan

Saat menggunakan WebApplication (lihat Migrasi dari ASP.NET Core di .NET 5 ke .NET 6), app.UseRouting harus dipanggil setelahnya UsePathBase sehingga middleware perutean dapat mengamati jalur yang dimodifikasi sebelum mencocokkan rute. Jika tidak, rute dicocokkan sebelum UsePathBase menulis ulang jalur seperti yang dijelaskan dalam ASP.NET Core Middleware dan Routing di ASP.NET Core.

Jalur asli dan dasar jalur diterapkan kembali ketika middleware dipanggil lagi secara terbalik. Untuk informasi selengkapnya tentang pemrosesan pesanan middleware, lihat ASP.NET Core Middleware.

Jika proksi memangkas jalur (misalnya, meneruskan /foo/api/1 ke /api/1), perbaiki pengalihan dan tautan dengan mengatur properti PathBase permintaan:

app.Use((context, next) =>
{
    context.Request.PathBase = new PathString("/foo");
    return next(context);
});

Jika proksi menambahkan data jalur, buang sebagian jalur untuk memperbaiki pengalihan dan tautan dengan menggunakan StartsWithSegments dan tetapkan ke properti Path:

app.Use((context, next) =>
{
    if (context.Request.Path.StartsWithSegments("/foo", out var remainder))
    {
        context.Request.Path = remainder;
    }

    return next(context);
});

Konfigurasi untuk proksi yang menggunakan nama header yang berbeda

Jika proksi tidak menggunakan header bernama X-Forwarded-For dan X-Forwarded-Proto untuk meneruskan alamat/port proksi dan informasi skema asal, atur ForwardedForHeaderName opsi dan ForwardedProtoHeaderName agar sesuai dengan nama header yang digunakan oleh proksi:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.Configure<ForwardedHeadersOptions>(options =>
{
    options.ForwardedForHeaderName = "HeaderNamUsedByProxy_X-Forwarded-For_Header";
    options.ForwardedProtoHeaderName = "HeaderNamUsedByProxy_X-Forwarded-Proto_Header";
});

var app = builder.Build();

app.UseForwardedHeaders();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseAuthorization();

app.MapRazorPages();

app.Run();

Teruskan skema untuk proksi terbalik Linux dan non-IIS

Aplikasi yang memanggil UseHttpsRedirection dan UseHsts menempatkan situs ke dalam perulangan tak terbatas jika disebarkan ke Azure Linux App Service, komputer virtual (VM) Azure Linux, atau di belakang proksi terbalik lainnya selain IIS. Proksi terbalik mengakhiri koneksi TLS, dan Kestrel tidak diberi tahu tentang skema permintaan yang benar. OAuth dan OIDC juga gagal dalam konfigurasi ini karena menghasilkan pengalihan yang salah. UseIISIntegration menambahkan dan mengonfigurasi Middleware Header yang Diteruskan saat berjalan di belakang IIS, tetapi tidak ada konfigurasi otomatis yang cocok untuk Linux (integrasi Apache atau Nginx).

Untuk meneruskan skema dari proksi dalam skenario non-IIS, aktifkan Middleware Header yang Diteruskan dengan mengatur ASPNETCORE_FORWARDEDHEADERS_ENABLED ke true. Peringatan: Bendera ini menggunakan pengaturan yang dirancang untuk lingkungan cloud dan tidak mengaktifkan fitur seperti KnownProxies option untuk membatasi penerus IP mana yang diterima.

Penerusan sertifikat

Azure

Untuk mengonfigurasi Azure App Service untuk penerusan sertifikat, lihat Mengonfigurasi autentikasi bersama TLS untuk Azure App Service. Panduan berikut berkaitan dengan mengonfigurasi aplikasi ASP.NET Core.

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.AddCertificateForwarding(options =>
    options.CertificateHeader = "X-ARR-ClientCert");

var app = builder.Build();

app.UseCertificateForwarding();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseAuthorization();
app.UseAuthentication();

app.MapRazorPages();

app.Run();

Proksi web lainnya

Jika proksi yang digunakan bukan Perutean Permintaan Aplikasi (ARR) Azure App Service atau IIS, konfigurasikan proksi untuk meneruskan sertifikat yang diterimanya di header HTTP.

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.AddCertificateForwarding(options =>
    options.CertificateHeader = "YOUR_CERTIFICATE_HEADER_NAME");

var app = builder.Build();

app.UseCertificateForwarding();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseAuthorization();
app.UseAuthentication();

app.MapRazorPages();

app.Run();

Jika proksi tidak mengodekan sertifikat base64, seperti halnya dengan Nginx, atur opsi HeaderConverter. Pertimbangkan contoh berikut:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.AddCertificateForwarding(options =>
{
    options.CertificateHeader = "YOUR_CUSTOM_HEADER_NAME";
    options.HeaderConverter = (headerValue) =>
    {
        // Conversion logic to create an X509Certificate2.
        var clientCertificate = ConversionLogic.CreateAnX509Certificate2();
        return clientCertificate;
    };
});

var app = builder.Build();

app.UseCertificateForwarding();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseAuthorization();
app.UseAuthentication();

app.MapRazorPages();

app.Run();

Pecahkan masalah

Ketika header tidak diteruskan seperti yang diharapkan, aktifkan tingkat debug dan pengelogan permintaan HTTP. UseHttpLogging harus dipanggil setelah UseForwardedHeaders:

using Microsoft.AspNetCore.HttpLogging;
using Microsoft.AspNetCore.HttpOverrides;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();

builder.Services.AddHttpLogging(options =>
{
    options.LoggingFields = HttpLoggingFields.RequestPropertiesAndHeaders;
});

builder.Services.Configure<ForwardedHeadersOptions>(options =>
{
    options.ForwardedHeaders =
        ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto;
});

var app = builder.Build();

app.UseForwardedHeaders();
app.UseHttpLogging();

app.Use(async (context, next) =>
{
    // Connection: RemoteIp
    app.Logger.LogInformation("Request RemoteIp: {RemoteIpAddress}",
        context.Connection.RemoteIpAddress);

    await next(context);
});

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseAuthorization();

app.MapRazorPages();

app.Run();

Jika ada beberapa nilai di header tertentu, Middleware Header yang Diteruskan memproses header dalam urutan terbalik dari kanan ke kiri. Nilai default ForwardLimit adalah 1 (satu), jadi hanya nilai paling kanan dari header-header yang diproses kecuali nilai ForwardLimit ditingkatkan.

IP remote asli dari permintaan harus cocok dengan entri dalam daftar KnownProxies atau KnownNetworks sebelum header yang diteruskan diproses. Ini membatasi spoofing header dengan tidak menerima penerus dari proksi yang tidak tepercaya. Ketika proksi yang tidak diketahui terdeteksi, pengelogan menunjukkan alamat proksi:

September 20th 2018, 15:49:44.168 Unknown proxy: 10.0.0.100:54321

Dalam contoh sebelumnya, 10.0.0.100 adalah server proksi. Jika server adalah proksi tepercaya, tambahkan alamat IP server ke KnownProxies, atau tambahkan jaringan tepercaya ke KnownNetworks. Untuk informasi selengkapnya, lihat bagian Opsi Middleware Header yang Diteruskan.

using Microsoft.AspNetCore.HttpOverrides;
using System.Net;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorPages();
builder.Services.Configure<ForwardedHeadersOptions>(options =>
{
    options.ForwardedHeaders =
        ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto;
    options.KnownProxies.Add(IPAddress.Parse("10.0.0.100"));
});

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    app.UseForwardedHeaders();
    app.UseHsts();
}
else
{
    app.UseDeveloperExceptionPage();
    app.UseForwardedHeaders();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseAuthorization();

app.MapRazorPages();

app.Run();

Untuk menampilkan log, tambahkan "Microsoft.AspNetCore.HttpLogging": "Information" ke appsettings.Development.json file:

{
  "DetailedErrors": true,
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning",
      "Microsoft.AspNetCore.HttpLogging": "Information"
    }
  }
}

Penting

Hanya izinkan proksi dan jaringan tepercaya untuk meneruskan header. Jika tidak, serangan spoofing IP dimungkinkan .

Sumber Daya Tambahan:

Dalam konfigurasi yang direkomendasikan untuk ASP.NET Core, aplikasi dihosting menggunakan Modul IIS/ASP.NET Core, Nginx, atau Apache. Proxy server, load balancer, dan perangkat jaringan lainnya sering mengaburkan informasi tentang permintaan sebelum mencapai aplikasi.

  • Ketika permintaan HTTPS diproksi melalui HTTP, skema asli (HTTPS) hilang dan harus diteruskan di header.
  • Karena aplikasi menerima permintaan dari proksi dan bukan sumber sebenarnya di Internet atau jaringan perusahaan, alamat IP klien asal juga harus diteruskan di header.

Informasi ini mungkin penting dalam pemrosesan permintaan, misalnya dalam pengalihan, autentikasi, pembuatan tautan, evaluasi kebijakan, dan geolokasi klien.

Header yang diteruskan

Menurut konvensi, proksi meneruskan informasi di header HTTP.

Kepala Halaman Deskripsi
X-Forwarded-For Menyimpan informasi tentang klien yang memulai permintaan dan proksi berikutnya dalam rantai proksi. Parameter ini mungkin berisi alamat IP (dan, secara opsional, nomor port). Dalam rantai server proksi, parameter pertama menunjukkan klien tempat permintaan pertama kali dibuat. Pengidentifikasi proksi berikutnya mengikuti. Proksi terakhir dalam rantai tidak ada dalam daftar parameter. Alamat IP proksi terakhir, dan secara opsional nomor port, tersedia sebagai alamat IP jarak jauh di lapisan transportasi.
X-Forwarded-Proto Nilai skema asal (HTTP/HTTPS). Nilai mungkin juga merupakan daftar skema jika permintaan telah melintasi beberapa proksi.
X-Forwarded-Host Nilai asli bidang header Host. Biasanya, proksi tidak mengubah header Host. Lihat Microsoft Security Advisory CVE-2018-0787 untuk informasi tentang kerentanan elevasi hak istimewa yang memengaruhi sistem di mana proksi tidak memvalidasi atau membatasi header Host ke nilai yang diketahui baik.

Middleware Penerusan Header (ForwardedHeadersMiddleware) membaca header ini dan mengisi bidang terkait pada HttpContext.

Pembaruan middleware:

Untuk informasi selengkapnya tentang sebelumnya, lihat masalah GitHub ini.

Pengaturan default Middleware Header yang Diteruskan dapat dikonfigurasi. Untuk pengaturan default:

  • Hanya ada satu proksi antara aplikasi dan sumber permintaan.
  • Hanya alamat loopback yang dikonfigurasi untuk proksi yang diketahui dan jaringan yang diketahui.
  • Header yang diteruskan diberi nama X-Forwarded-For dan X-Forwarded-Proto.
  • Nilai ForwardedHeaders adalah ForwardedHeaders.None; forwarder yang diinginkan harus diatur di sini untuk mengaktifkan middleware.

Tidak semua perangkat jaringan secara otomatis menambahkan header X-Forwarded-For dan X-Forwarded-Proto tanpa konfigurasi tambahan. Lihat panduan produsen perangkat Anda jika permintaan terproksi tidak berisi header ini ketika mencapai aplikasi. Jika perangkat menggunakan nama header yang berbeda dari X-Forwarded-For dan X-Forwarded-Proto, atur opsi ForwardedForHeaderName dan ForwardedProtoHeaderName agar sesuai dengan nama header yang digunakan oleh perangkat. Untuk informasi selengkapnya, lihat Opsi Middleware Header yang Diteruskan dan Konfigurasi untuk proksi yang menggunakan nama header yang berbeda.

Modul IIS/IIS Express dan ASP.NET Core

IIS Integration Middleware mengaktifkan Forwarded Headers Middleware secara default saat aplikasi dihosting out-of-process menggunakan IIS dan Modul ASP.NET Core. Middleware Header yang Diteruskan diaktifkan untuk dijalankan pertama kali dalam alur middleware dengan konfigurasi terbatas yang spesifik untuk Modul ASP.NET Core karena masalah kepercayaan terkait header yang diteruskan (contohnya, pemalsuan IP). Middleware dikonfigurasi untuk meneruskan header X-Forwarded-For dan X-Forwarded-Proto serta dibatasi hanya pada satu proxy localhost. Jika konfigurasi tambahan diperlukan, lihat opsi Middleware Header yang Diteruskan.

Skenario server proksi dan load balancer lainnya

Di luar penggunaan Integrasi IIS saat menghosting di luar proses, Middleware Header yang Diteruskan tidak diaktifkan secara default. Middleware "Forwarded Headers" harus diaktifkan agar aplikasi memproses header yang diteruskan dengan UseForwardedHeaders. Setelah mengaktifkan middleware, jika tidak ada ForwardedHeadersOptions yang ditentukan ke middleware, ForwardedHeadersOptions.ForwardedHeaders default adalah ForwardedHeaders.None.

Konfigurasikan middleware dengan ForwardedHeadersOptions untuk meneruskan header X-Forwarded-For dan X-Forwarded-Proto di Startup.ConfigureServices.

Urutan Middleware Header yang Diteruskan

Middleware Header yang Diteruskan harus dijalankan sebelum middleware lainnya. Urutan ini memastikan bahwa middleware yang mengandalkan informasi header yang diteruskan dapat memanfaatkan data header untuk pemrosesan. Middleware Penerusan Header dapat berjalan setelah proses diagnostik dan penanganan kesalahan, tetapi harus dijalankan terlebih dahulu sebelum memanggil UseHsts.

public class Startup
{
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddControllersWithViews();
        services.Configure<ForwardedHeadersOptions>(options =>
        {
            options.ForwardedHeaders =
                ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto;
        });
    }

    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
            app.UseForwardedHeaders();
        }
        else
        {
            app.UseExceptionHandler("/Home/Error");
            app.UseForwardedHeaders();
            app.UseHsts();
        }

        app.UseHttpsRedirection();
        app.UseStaticFiles();

        app.UseRouting();

        app.UseAuthorization();

        app.UseEndpoints(endpoints =>
        {
            endpoints.MapControllerRoute(
                name: "default",
                pattern: "{controller=Home}/{action=Index}/{id?}");
        });
    }
}

Atau, panggil UseForwardedHeaders sebelum diagnostik:

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

    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseExceptionHandler("/Home/Error");
        app.UseHsts();
    }

    app.UseHttpsRedirection();
    app.UseStaticFiles();

    app.UseRouting();

    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllerRoute(
            name: "default",
            pattern: "{controller=Home}/{action=Index}/{id?}");
    });
}

Catatan

Jika tidak ada ForwardedHeadersOptions yang ditentukan dalam Startup.ConfigureServices atau langsung ke metode ekstensi dengan UseForwardedHeaders, header default yang akan diteruskan adalah ForwardedHeaders.None. Properti ForwardedHeaders harus dikonfigurasi dengan header untuk diteruskan.

Konfigurasi Nginx

Untuk meneruskan X-Forwarded-For header dan X-Forwarded-Proto , lihat Host ASP.NET Core di Linux dengan Nginx.

Konfigurasi Apache

X-Forwarded-For ditambahkan secara otomatis (lihat Modul Apache mod_proxy: Header Permintaan Proksi Pembalik).

Opsi Middleware Header yang Diteruskan

ForwardedHeadersOptions mengontrol perilaku Middleware Header yang Diteruskan. Contoh berikut mengubah nilai default:

  • Batasi jumlah entri di header yang diteruskan ke 2.
  • Tambahkan alamat proksi yang diketahui dari 127.0.10.1.
  • Ubah nama header yang diteruskan dari default X-Forwarded-For menjadi X-Forwarded-For-My-Custom-Header-Name.
services.Configure<ForwardedHeadersOptions>(options =>
{
    options.ForwardLimit = 2;
    options.KnownProxies.Add(IPAddress.Parse("127.0.10.1"));
    options.ForwardedForHeaderName = "X-Forwarded-For-My-Custom-Header-Name";
});
Opsi Deskripsi
AllowedHosts Membatasi host berdasarkan header X-Forwarded-Host ke nilai yang disediakan.
  • Nilai dibandingkan menggunakan ordinal-ignore-case.
  • Nomor port harus dikecualikan.
  • Jika daftar kosong, semua host diizinkan.
  • Kartu wildcard * tingkat atas memungkinkan semua host yang tidak kosong.
  • Wildcard subdomain diizinkan tetapi tidak cocok dengan domain akar. Misalnya, *.contoso.com cocok dengan subdomain foo.contoso.com tetapi bukan domain contoso.comakar .
  • Nama host Unicode diizinkan tetapi dikonversi ke Punycode untuk pencocokan.
  • Alamat IPv6 harus menyertakan tanda kurung batas dan berada dalam bentuk konvensional (misalnya, [ABCD:EF01:2345:6789:ABCD:EF01:2345:6789]). Alamat IPv6 tidak ditangani secara khusus untuk memeriksa kesetaraan logis antara format yang berbeda, dan tidak ada kanonisasi yang dilakukan.
  • Kegagalan untuk membatasi host yang diizinkan mungkin memungkinkan cyberattacker untuk memalsukan tautan yang dihasilkan oleh layanan.
Nilai defaultnya adalah kosong IList<string>.
ForwardedHeaders Mengidentifikasi penerus mana yang harus diproses. Lihat ForwardedHeaders Enum untuk daftar bidang yang berlaku. Nilai umum yang ditetapkan ke properti ini adalah ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto.

Nilai defaultnya adalah ForwardedHeaders.None.
ForwardedForHeaderName Gunakan header yang ditentukan oleh properti ini alih-alih yang ditentukan oleh ForwardedHeadersDefaults.XForwardedForHeaderName. Opsi ini digunakan ketika proksi/penerus tidak menggunakan X-Forwarded-For header tetapi menggunakan beberapa header lain untuk meneruskan informasi.

Default adalah X-Forwarded-For.
ForwardedHostHeaderName Gunakan header yang ditentukan oleh properti ini alih-alih yang ditentukan oleh ForwardedHeadersDefaults.XForwardedHostHeaderName. Opsi ini digunakan ketika proksi/penerus tidak menggunakan X-Forwarded-Host header tetapi menggunakan beberapa header lain untuk meneruskan informasi.

Default adalah X-Forwarded-Host.
ForwardedProtoHeaderName Gunakan header yang ditentukan oleh properti ini alih-alih yang ditentukan oleh ForwardedHeadersDefaults.XForwardedProtoHeaderName. Opsi ini digunakan ketika proksi/penerus tidak menggunakan X-Forwarded-Proto header tetapi menggunakan beberapa header lain untuk meneruskan informasi.

Default adalah X-Forwarded-Proto.
ForwardedPrefixHeaderName Gunakan header yang ditentukan oleh properti ini alih-alih yang ditentukan oleh ForwardedHeadersDefaults.XForwardedPrefixHeaderName. Opsi ini digunakan ketika proksi/penerus tidak menggunakan X-Forwarded-Prefix header tetapi menggunakan beberapa header lain untuk meneruskan informasi.

Default adalah X-Forwarded-Prefix.
ForwardLimit Membatasi jumlah entri dalam header yang diproses. Atur ke null untuk menonaktifkan batas, tetapi ini hanya boleh dilakukan jika KnownProxies atau KnownNetworks dikonfigurasi. Mengatur nilai selainnull adalah tindakan pencegahan (tetapi bukan jaminan) untuk melindungi dari proksi yang salah dikonfigurasi dan permintaan berbahaya yang tiba dari saluran samping di jaringan.

Middleware Header yang diteruskan memproses header dalam urutan terbalik dari kanan ke kiri. Jika nilai default (1) digunakan, hanya nilai paling kanan dari header yang diproses kecuali nilai ForwardLimit ditingkatkan.

Default adalah 1.
KnownNetworks Rentang alamat jaringan yang diketahui untuk menerima header yang diteruskan. Berikan rentang IP menggunakan notasi Classless Interdomain Routing (CIDR).

Jika server menggunakan soket mode ganda, alamat IPv4 disediakan dalam format IPv6 (misalnya, 10.0.0.1 dalam IPv4 yang diwakili dalam IPv6 sebagai ::ffff:10.0.0.1). Lihat IPAddress.MapToIPv6. Tentukan apakah format ini diperlukan dengan melihat HttpContext.Connection.RemoteIpAddress.

Defaultnya adalah IList<IPNetwork> yang berisi satu entri untuk new IPNetwork(IPAddress.Loopback, 8).
KnownProxies Alamat proksi yang diketahui untuk menerima header yang diteruskan. Gunakan KnownProxies untuk menentukan kecocokan alamat IP yang tepat.

Jika server menggunakan soket mode ganda, alamat IPv4 disediakan dalam format IPv6 (misalnya, 10.0.0.1 dalam IPv4 yang diwakili dalam IPv6 sebagai ::ffff:10.0.0.1). Lihat IPAddress.MapToIPv6. Tentukan apakah format ini diperlukan dengan melihat HttpContext.Connection.RemoteIpAddress.

Defaultnya adalah IList<IPAddress> yang berisi satu entri untuk IPAddress.IPv6Loopback.
OriginalForHeaderName Gunakan header yang ditentukan oleh properti ini alih-alih yang ditentukan oleh ForwardedHeadersDefaults.XOriginalForHeaderName.

Default adalah X-Original-For.
OriginalHostHeaderName Gunakan header yang ditentukan oleh properti ini alih-alih yang ditentukan oleh ForwardedHeadersDefaults.XOriginalHostHeaderName.

Default adalah X-Original-Host.
OriginalProtoHeaderName Gunakan header yang ditentukan oleh properti ini alih-alih yang ditentukan oleh ForwardedHeadersDefaults.XOriginalProtoHeaderName.

Default adalah X-Original-Proto.
OriginalPrefixHeaderName Gunakan header yang ditentukan oleh properti ini alih-alih yang ditentukan oleh ForwardedHeadersDefaults.XOriginalPrefixHeaderName.

Default adalah X-Original-Prefix.
RequireHeaderSymmetry Mengharuskan jumlah nilai header selaras dengan ForwardedHeadersOptions.ForwardedHeaders yang sedang diproses.

Default dalam ASP.NET Core 1.x adalah true. Default dalam ASP.NET Core 2.0 atau yang lebih baru adalah false.

Skenario dan kasus penggunaan

Ketika tidak dimungkinkan untuk menambahkan header yang diteruskan serta semua permintaan telah aman

Dalam beberapa kasus, mungkin tidak mungkin untuk menambahkan header yang diteruskan ke permintaan yang diproksikan ke aplikasi. Jika proksi memastikan bahwa semua permintaan eksternal publik adalah HTTPS, skema dapat diatur Startup.Configure secara manual sebelum menggunakan jenis middleware apa pun.

app.Use((context, next) =>
{
    context.Request.Scheme = "https";
    return next();
});

Kode ini dapat dinonaktifkan dengan variabel lingkungan atau pengaturan konfigurasi lainnya dalam lingkungan pengembangan atau penahapan.

Menangani basis jalur dan proksi yang mengubah jalur permintaan

Beberapa proxy melewati path secara utuh tetapi dengan path dasar aplikasi yang harus dihapus supaya perutean berfungsi dengan baik. Middleware UsePathBaseExtensions.UsePathBase membagi jalur menjadi HttpRequest.Path dan jalur dasar aplikasi ke HttpRequest.PathBase.

Jika /foo adalah jalur dasar aplikasi untuk jalur proksi yang diteruskan sebagai /foo/api/1, middleware mengatur Request.PathBase ke /foo dan Request.Path ke /api/1 dengan perintah berikut:

app.UsePathBase("/foo");

Jalur asli dan dasar jalur diterapkan kembali ketika middleware dipanggil lagi secara terbalik. Untuk informasi selengkapnya tentang pemrosesan pesanan middleware, lihat ASP.NET Core Middleware.

Jika proksi memangkas jalur (misalnya, meneruskan /foo/api/1 ke /api/1), perbaiki pengalihan dan tautan dengan mengatur properti PathBase permintaan:

app.Use((context, next) =>
{
    context.Request.PathBase = new PathString("/foo");
    return next();
});

Jika proksi menambahkan data jalur, buang sebagian jalur untuk memperbaiki pengalihan dan tautan dengan menggunakan StartsWithSegments dan tetapkan ke properti Path:

app.Use((context, next) =>
{
    if (context.Request.Path.StartsWithSegments("/foo", out var remainder))
    {
        context.Request.Path = remainder;
    }

    return next();
});

Konfigurasi untuk proksi yang menggunakan nama header yang berbeda

Jika proksi tidak menggunakan header bernama X-Forwarded-For dan X-Forwarded-Proto untuk meneruskan alamat/port proksi dan informasi skema asal, atur ForwardedForHeaderName opsi dan ForwardedProtoHeaderName agar sesuai dengan nama header yang digunakan oleh proksi:

services.Configure<ForwardedHeadersOptions>(options =>
{
    options.ForwardedForHeaderName = "Header_Name_Used_By_Proxy_For_X-Forwarded-For_Header";
    options.ForwardedProtoHeaderName = "Header_Name_Used_By_Proxy_For_X-Forwarded-Proto_Header";
});

Teruskan skema untuk proksi terbalik Linux dan non-IIS

Aplikasi yang memanggil UseHttpsRedirection dan UseHsts menempatkan situs ke dalam perulangan tak terbatas jika disebarkan ke Azure Linux App Service, komputer virtual (VM) Azure Linux, atau di belakang proksi terbalik lainnya selain IIS. Proksi terbalik mengakhiri TLS, dan Kestrel tidak mengetahui skema permintaan yang benar. OAuth dan OIDC juga gagal dalam konfigurasi ini karena menghasilkan pengalihan yang salah. UseIISIntegration menambahkan dan mengonfigurasi Middleware Header yang Diteruskan saat berjalan di belakang IIS, tetapi tidak ada konfigurasi otomatis yang cocok untuk Linux (integrasi Apache atau Nginx).

Untuk meneruskan skema dari proksi dalam skenario non-IIS, tambahkan dan konfigurasikan Forwarded Headers Middleware. Di Startup.ConfigureServices, gunakan kode berikut:

// using Microsoft.AspNetCore.HttpOverrides;

if (string.Equals(
    Environment.GetEnvironmentVariable("ASPNETCORE_FORWARDEDHEADERS_ENABLED"),
    "true", StringComparison.OrdinalIgnoreCase))
{
    services.Configure<ForwardedHeadersOptions>(options =>
    {
        options.ForwardedHeaders = ForwardedHeaders.XForwardedFor |
            ForwardedHeaders.XForwardedProto;
        // Only loopback proxies are allowed by default.
        // Clear that restriction because forwarders are enabled by explicit
        // configuration.
        options.KnownNetworks.Clear();
        options.KnownProxies.Clear();
    });
}

Penerusan sertifikat

Azure

Untuk mengonfigurasi Azure App Service untuk penerusan sertifikat, lihat Mengonfigurasi autentikasi bersama TLS untuk Azure App Service. Panduan berikut berkaitan dengan mengonfigurasi aplikasi ASP.NET Core.

Di Startup.Configure, tambahkan kode berikut sebelum panggilan ke app.UseAuthentication();:

app.UseCertificateForwarding();

Konfigurasikan Middleware Penerusan Sertifikat untuk menentukan nama header yang digunakan Azure. Di Startup.ConfigureServices, tambahkan kode berikut untuk mengonfigurasi header tempat middleware membangun sertifikat:

services.AddCertificateForwarding(options =>
    options.CertificateHeader = "X-ARR-ClientCert");

Proksi web lainnya

Jika proksi yang digunakan bukan Perutean Permintaan Aplikasi (ARR) Azure App Service atau IIS, konfigurasikan proksi untuk meneruskan sertifikat yang diterimanya di header HTTP. Di Startup.Configure, tambahkan kode berikut sebelum panggilan ke app.UseAuthentication();:

app.UseCertificateForwarding();

Konfigurasikan Middleware Penerusan Sertifikat untuk menentukan nama header. Di Startup.ConfigureServices, tambahkan kode berikut untuk mengonfigurasi header tempat middleware membangun sertifikat:

services.AddCertificateForwarding(options =>
    options.CertificateHeader = "YOUR_CERTIFICATE_HEADER_NAME");

Jika proksi tidak mengodekan sertifikat base64 (seperti halnya dengan Nginx), atur HeaderConverter opsi . Pertimbangkan contoh berikut di Startup.ConfigureServices:

services.AddCertificateForwarding(options =>
{
    options.CertificateHeader = "YOUR_CUSTOM_HEADER_NAME";
    options.HeaderConverter = (headerValue) =>
    {
        var clientCertificate =
           /* some conversion logic to create an X509Certificate2 */
        return clientCertificate;
    }
});

Pecahkan masalah

Saat header tidak diteruskan seperti yang diharapkan, aktifkan pengelogan. Jika log tidak memberikan informasi yang memadai untuk memecahkan masalah, hitung header permintaan yang diterima oleh server. Gunakan middleware sebaris untuk menulis header permintaan ke respons aplikasi atau mencatat header.

Untuk menulis header ke respons aplikasi, letakkan middleware terminal sebaris berikut segera setelah panggilan ke UseForwardedHeaders di Startup.Configure:

app.Run(async (context) =>
{
    context.Response.ContentType = "text/plain";

    // Request method, scheme, and path
    await context.Response.WriteAsync(
        $"Request Method: {context.Request.Method}{Environment.NewLine}");
    await context.Response.WriteAsync(
        $"Request Scheme: {context.Request.Scheme}{Environment.NewLine}");
    await context.Response.WriteAsync(
        $"Request Path: {context.Request.Path}{Environment.NewLine}");

    // Headers
    await context.Response.WriteAsync($"Request Headers:{Environment.NewLine}");

    foreach (var header in context.Request.Headers)
    {
        await context.Response.WriteAsync($"{header.Key}: " +
            $"{header.Value}{Environment.NewLine}");
    }

    await context.Response.WriteAsync(Environment.NewLine);

    // Connection: RemoteIp
    await context.Response.WriteAsync(
        $"Request RemoteIp: {context.Connection.RemoteIpAddress}");
});

Anda dapat menulis ke log alih-alih isi respons. Menulis ke log memungkinkan situs berfungsi secara normal selama debugging.

Untuk menulis log daripada ke isi respons:

  • Masukkan ILogger<Startup> ke dalam kelas Startup seperti yang dijelaskan dalam Membuat pesan log.
  • Tempatkan middleware sebaris berikut segera setelah panggilan ke UseForwardedHeaders di Startup.Configure.
app.Use(async (context, next) =>
{
    // Request method, scheme, path, and base path
    _logger.LogDebug("Request Method: {Method}", context.Request.Method);
    _logger.LogDebug("Request Scheme: {Scheme}", context.Request.Scheme);
    _logger.LogDebug("Request Path: {Path}", context.Request.Path);
    _logger.LogDebug("Request Path Base: {PathBase}", context.Request.PathBase);

    // Headers
    foreach (var header in context.Request.Headers)
    {
        _logger.LogDebug("Header: {Key}: {Value}", header.Key, header.Value);
    }

    // Connection: RemoteIp
    _logger.LogDebug("Request RemoteIp: {RemoteIpAddress}",
        context.Connection.RemoteIpAddress);

    await next();
});

Saat diproses, X-Forwarded-{For|Proto|Host|Prefix} nilai dipindahkan ke X-Original-{For|Proto|Host|Prefix}. Jika ada beberapa nilai di header tertentu, Middleware Header yang Diteruskan memproses header dalam urutan terbalik dari kanan ke kiri. Nilai default ForwardLimit adalah 1 (satu), jadi hanya nilai paling kanan dari header-header yang diproses kecuali nilai ForwardLimit ditingkatkan.

IP remote asli dari permintaan harus cocok dengan entri dalam daftar KnownProxies atau KnownNetworks sebelum header yang diteruskan diproses. Ini membatasi spoofing header dengan tidak menerima penerus dari proksi yang tidak tepercaya. Ketika proksi yang tidak diketahui terdeteksi, pengelogan menunjukkan alamat proksi:

September 20th 2018, 15:49:44.168 Unknown proxy: 10.0.0.100:54321

Dalam contoh sebelumnya, 10.0.0.100 adalah server proksi. Jika server adalah proksi tepercaya, tambahkan alamat IP server ke KnownProxies (atau tambahkan jaringan tepercaya ke KnownNetworks) di Startup.ConfigureServices. Untuk informasi selengkapnya, lihat bagian Opsi Middleware Header yang Diteruskan.

services.Configure<ForwardedHeadersOptions>(options =>
{
    options.KnownProxies.Add(IPAddress.Parse("10.0.0.100"));
});

Penting

Hanya izinkan proksi dan jaringan tepercaya untuk meneruskan header. Jika tidak, serangan spoofing IP dimungkinkan .

Sumber Daya Tambahan: