Bagikan melalui


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 8 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 8 dari artikel ini.

Penting

Informasi ini berkaitan dengan produk pra-rilis yang mungkin dimodifikasi secara substansial sebelum dirilis secara komersial. Microsoft tidak memberikan jaminan, tersirat maupun tersurat, sehubungan dengan informasi yang diberikan di sini.

Untuk rilis saat ini, lihat versi .NET 8 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. Server proksi, load balancer, dan appliance 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 harus membaca Host ASP.NET Core di farm web.

Header yang diteruskan

Menurut konvensi, proksi meneruskan informasi di header HTTP.

Header 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 Header yang Diteruskan, 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.
  • Nilainya ForwardedHeaders adalah ForwardedHeaders.None, penerus yang diinginkan harus diatur di sini untuk mengaktifkan middleware.

Tidak semua appliance jaringan menambahkan X-Forwarded-For header dan X-Forwarded-Proto tanpa konfigurasi tambahan. Lihat panduan produsen appliance Anda jika permintaan yang diproksi tidak berisi header ini saat mencapai aplikasi. Jika appliance menggunakan nama header yang berbeda dari X-Forwarded-For dan X-Forwarded-Proto, atur ForwardedForHeaderName opsi dan ForwardedProtoHeaderName agar sesuai dengan nama header yang digunakan oleh appliance. 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

Middleware Header yang Diteruskan diaktifkan secara default oleh IIS Integration Middleware ketika aplikasi dihosting di luar proses 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 disebabkan oleh masalah kepercayaan dengan header yang diteruskan, misalnya, spoofing IP. Middleware dikonfigurasi untuk meneruskan X-Forwarded-For header dan X-Forwarded-Proto dan dibatasi untuk satu proksi 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 Header yang Diteruskan harus diaktifkan agar aplikasi memproses header yang diteruskan dengan UseForwardedHeaders. Setelah mengaktifkan middleware jika tidak ForwardedHeadersOptions 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 Header yang Diteruskan harus berjalan sebelum middleware lainnya. Urutan ini memastikan bahwa middleware yang mengandalkan informasi header yang diteruskan dapat menggunakan nilai header untuk pemrosesan. Middleware Header yang Diteruskan dapat berjalan setelah diagnostik dan penanganan kesalahan, tetapi harus dijalankan 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. Untuk informasi selengkapnya, lihat NGINX: Menggunakan header Yang Diteruskan.

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 Middleware Header yang Diteruskan. 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 menurut X-Forwarded-Host header ke nilai yang disediakan.
  • Nilai dibandingkan menggunakan ordinal-ignore-case.
  • Nomor port harus dikecualikan.
  • Jika daftar kosong, semua host diizinkan.
  • Kartubebas * 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 khusus untuk memeriksa kesetaraan logis antara format yang berbeda, dan tidak ada kanonisisasi yang dilakukan.
  • Kegagalan untuk membatasi host yang diizinkan dapat memungkinkan cyberattacker untuk spoof 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 Enum ForwardedHeaders 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 non-nilainull 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 berisi IList><IPNetworksatu 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 berisi IList><IPAddresssatu 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 disinkronkan antara 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 dan semua permintaan 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 proksi melewati jalur secara utuh tetapi dengan jalur dasar aplikasi yang harus dihapus sehingga 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 diatur 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 5.0 ke 6.0), app.UseRouting harus dipanggil setelah UsePathBase sehingga middleware perutean dapat mengamati jalur yang dimodifikasi sebelum mencocokkan rute. Jika tidak, rute dicocokkan sebelum jalur ditulis ulang oleh UsePathBase seperti yang dijelaskan dalam artikel Pengurutan Middleware dan Perutean.

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 bagian dari jalur untuk memperbaiki pengalihan dan tautan dengan menggunakan StartsWithSegments dan menetapkan ke Path properti:

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();

Meneruskan 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. TLS dihentikan oleh proksi terbalik, 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, 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.

  • Konfigurasikan Middleware Penerusan Sertifikat untuk menentukan nama header yang digunakan Azure. Tambahkan kode berikut untuk mengonfigurasi header tempat middleware membangun sertifikat.
  • Panggil UseCertificateForwarding sebelum panggilan ke UseAuthentication.
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 digunakan yang bukan IIS atau Perutean Permintaan Aplikasi (ARR) Azure App Service, 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 HeaderConverter opsi . 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 debug pengelogan tingkat 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. Defaultnya ForwardLimit adalah 1 (satu), jadi hanya nilai paling kanan dari header yang diproses kecuali nilainya ForwardLimit ditingkatkan.

IP jarak jauh asli permintaan harus cocok dengan entri dalam KnownProxies daftar 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. Server proksi, load balancer, dan appliance 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.

Header 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 Header yang Diteruskan (ForwardedHeadersMiddleware), membaca header ini dan mengisi bidang terkait pada HttpContext.

Pembaruan middleware:

  • HttpContext.Connection.RemoteIpAddress: Atur X-Forwarded-For menggunakan nilai header. Pengaturan tambahan memengaruhi bagaimana middleware diatur RemoteIpAddress. Untuk detailnya, lihat opsi Middleware Header yang Diteruskan. Nilai yang digunakan dihapus dari X-Forwarded-For, dan nilai lama dipertahankan dalam X-Original-For. Pola yang sama diterapkan ke header lain, Host dan Proto.
  • HttpContext.Request.Scheme: Atur X-Forwarded-Proto menggunakan nilai header.
  • HttpContext.Request.Host: Atur X-Forwarded-Host menggunakan nilai header.

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.
  • Nilainya ForwardedHeaders adalah ForwardedHeaders.None, penerus yang diinginkan harus diatur di sini untuk mengaktifkan middleware.

Tidak semua appliance jaringan menambahkan X-Forwarded-For header dan X-Forwarded-Proto tanpa konfigurasi tambahan. Lihat panduan produsen appliance Anda jika permintaan yang diproksi tidak berisi header ini saat mencapai aplikasi. Jika appliance menggunakan nama header yang berbeda dari X-Forwarded-For dan X-Forwarded-Proto, atur ForwardedForHeaderName opsi dan ForwardedProtoHeaderName agar sesuai dengan nama header yang digunakan oleh appliance. 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

Middleware Header yang Diteruskan diaktifkan secara default oleh IIS Integration Middleware saat aplikasi dihosting di luar proses di belakang IIS dan Modul Inti ASP.NET. Middleware Header yang Diteruskan diaktifkan untuk dijalankan terlebih dahulu di alur middleware dengan konfigurasi terbatas khusus untuk Modul inti ASP.NET karena masalah kepercayaan dengan header yang diteruskan (misalnya, spoofing IP). Middleware dikonfigurasi untuk meneruskan X-Forwarded-For header dan X-Forwarded-Proto dan dibatasi untuk satu proksi 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 Header yang Diteruskan harus diaktifkan agar aplikasi memproses header yang diteruskan dengan UseForwardedHeaders. Setelah mengaktifkan middleware jika tidak ForwardedHeadersOptions ditentukan ke middleware, ForwardedHeadersOptions.ForwardedHeaders default adalah ForwardedHeaders.None.

Konfigurasikan middleware dengan ForwardedHeadersOptions untuk meneruskan X-Forwarded-For header 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 menggunakan nilai header untuk pemrosesan. Middleware Header yang Diteruskan dapat berjalan setelah diagnostik dan penanganan kesalahan, tetapi harus dijalankan 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. Untuk informasi selengkapnya, lihat NGINX: Menggunakan header Yang Diteruskan.

Konfigurasi Apache

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

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 menurut X-Forwarded-Host header ke nilai yang disediakan.
  • Nilai dibandingkan menggunakan ordinal-ignore-case.
  • Nomor port harus dikecualikan.
  • Jika daftar kosong, semua host diizinkan.
  • Kartubebas * 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 khusus untuk memeriksa kesetaraan logis antara format yang berbeda, dan tidak ada kanonisisasi yang dilakukan.
  • Kegagalan untuk membatasi host yang diizinkan dapat memungkinkan cyberattacker untuk spoof tautan yang dihasilkan oleh layanan.
Nilai defaultnya adalah kosong IList<string>.
ForwardedHeaders Mengidentifikasi penerus mana yang harus diproses. Lihat Enum ForwardedHeaders 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 non-nilainull 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 berisi IList><IPNetworksatu 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 berisi IList><IPAddresssatu 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 disinkronkan antara 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 dan semua permintaan 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 Startup.Configure secara manual sebelum menggunakan semua jenis middleware:

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 proksi melewati jalur secara utuh tetapi dengan jalur dasar aplikasi yang harus dihapus sehingga 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 diatur 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 bagian dari jalur untuk memperbaiki pengalihan dan tautan dengan menggunakan StartsWithSegments dan menetapkan ke Path properti:

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";
});

Meneruskan 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. TLS dihentikan oleh proksi terbalik, 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 Middleware Header yang Diteruskan. 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 digunakan yang bukan IIS atau Perutean Permintaan Aplikasi (ARR) Azure App Service, 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 sebaris terminal 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 saat penelusuran kesalahan.

Untuk menulis log daripada ke isi respons:

  • ILogger<Startup> Masukkan ke kelas seperti yang Startup dijelaskan dalam Membuat log di Startup.
  • 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. Defaultnya ForwardLimit adalah 1 (satu), jadi hanya nilai paling kanan dari header yang diproses kecuali nilainya ForwardLimit ditingkatkan.

IP jarak jauh asli permintaan harus cocok dengan entri dalam KnownProxies daftar 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: