Catatan
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba masuk atau mengubah direktori.
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba mengubah direktori.
Oleh Fiyaz Hasan dan Rick Anderson
Pemalsuan permintaan lintas situs adalah serangan terhadap aplikasi yang dihosting web di mana aplikasi web berbahaya dapat memengaruhi interaksi antara browser klien dan aplikasi web yang mempercayai browser tersebut. Serangan ini dimungkinkan karena browser web mengirim beberapa jenis token autentikasi secara otomatis dengan setiap permintaan ke situs web. Bentuk eksploitasi ini juga dikenal sebagai serangan sekali klik atau pengambilalihan sesi karena serangan ini memanfaatkan sesi pengguna yang telah diautentikasi sebelumnya. Pemalsuan permintaan lintas situs juga dikenal sebagai XSRF atau CSRF.
Contoh serangan CSRF:
Pengguna masuk ke
www.good-banking-site.example.commenggunakan autentikasi formulir. Server mengautentikasi pengguna dan mengeluarkan respons yang menyertakan autentikasi cookie. Situs ini rentan terhadap serangan karena mempercayai permintaan apa pun yang diterimanya dengan autentikasi cookieyang valid.Pengguna mengunjungi situs berbahaya,
www.bad-crook-site.example.com.Situs berbahaya,
www.bad-crook-site.example.com, berisi formulir HTML yang mirip dengan contoh berikut:<h1>Congratulations! You're a Winner!</h1> <form action="https://www.good-banking-site.example.com/api/account" method="post"> <input type="hidden" name="Transaction" value="withdraw" /> <input type="hidden" name="Amount" value="1000000" /> <input type="submit" value="Click to collect your prize!" /> </form>Perhatikan bahwa formulir
actionmengirimkan data ke situs rentan, bukan ke situs berbahaya. Ini adalah bagian "lintas situs" dari CSRF.Pengguna memilih tombol kirim. Browser membuat permintaan dan secara otomatis menyertakan autentikasi cookie untuk domain yang diminta,
www.good-banking-site.example.com.Permintaan berjalan di
www.good-banking-site.example.comserver dengan konteks autentikasi pengguna dan dapat melakukan tindakan apa pun yang diizinkan untuk dilakukan oleh pengguna terautentikasi.
Selain skenario di mana pengguna memilih tombol untuk mengirimkan formulir, situs berbahaya dapat:
- Jalankan skrip yang secara otomatis mengirimkan formulir.
- Kirim pengiriman formulir sebagai permintaan AJAX.
- Sembunyikan formulir menggunakan CSS.
Skenario alternatif ini tidak memerlukan tindakan atau input apa pun dari pengguna selain awalnya mengunjungi situs berbahaya.
Menggunakan HTTPS tidak mencegah serangan CSRF. Situs berbahaya dapat mengirim sebuah permintaan https://www.good-banking-site.example.com/ semudah mengirim permintaan tidak aman.
Beberapa serangan menargetkan titik akhir yang merespons permintaan GET, dalam hal ini tag gambar dapat digunakan untuk melakukan tindakan. Bentuk serangan ini umum terjadi di situs forum yang mengizinkan gambar tetapi memblokir JavaScript. Aplikasi yang mengubah status pada permintaan GET, di mana variabel atau sumber daya diubah, rentan terhadap serangan berbahaya. Permintaan GET yang mengubah status tidak aman. Praktik terbaik adalah tidak pernah mengubah status pada permintaan GET.
Serangan CSRF dimungkinkan terhadap aplikasi web yang menggunakan cookie untuk autentikasi karena:
- Browser menyimpan cookie yang dikeluarkan oleh aplikasi web.
- Cookie tersimpan mencakup cookie sesi untuk pengguna yang diautentikasi.
- Browser mengirim semua cookie yang terkait dengan domain ke aplikasi web setiap permintaan terlepas dari bagaimana permintaan ke aplikasi dihasilkan dalam browser.
Namun, serangan CSRF tidak terbatas pada mengeksploitasi cookie. Misalnya, autentikasi Dasar dan Digest juga rentan. Setelah pengguna masuk dengan autentikasi Dasar atau Digest, browser secara otomatis mengirimkan kredensial pengguna hingga sesi berakhir.
Dalam konteks ini, sesi mengacu pada sesi sisi klien tempat pengguna diautentikasi. Ini tidak terkait dengan sesi sisi server atau middleware sesi ASP.NET Core.
Pengguna dapat melindungi dari kerentanan CSRF dengan mengambil tindakan pencegahan:
- Keluar dari aplikasi web setelah selesai menggunakannya.
- Hapus cookie browser secara berkala.
Namun, kerentanan CSRF pada dasarnya merupakan masalah dengan aplikasi web, bukan pengguna akhir.
Dasar-dasar autentikasi
Autentikasi berbasis Cookie adalah bentuk autentikasi yang populer. Sistem autentikasi berbasis token semakin populer, terutama untuk Aplikasi Halaman Tunggal (SPAs).
Cookie-berbasis autentikasi
Saat pengguna mengautentikasi menggunakan nama pengguna dan kata sandi mereka, mereka mengeluarkan token yang berisi tiket autentikasi. Token dapat digunakan untuk autentikasi dan otorisasi. Token disimpan sebagai cookie yang dikirim dengan setiap permintaan yang dilakukan klien. Pembuatan dan validasi cookie ini dilakukan menggunakan middleware autentikasi cookie. Middleware mengubah prinsipal pengguna menjadi data terenkripsi cookie. Pada permintaan berikutnya, middleware memvalidasi cookie, membuat ulang entitas utama, dan menetapkan entitas utama ke properti HttpContext.User.
Autentikasi berbasis token
Saat pengguna diautentikasi, mereka diberikan token (bukan token antiforgery). Token berisi informasi pengguna dalam bentuk klaim atau token referensi yang menunjuk aplikasi ke status pengguna yang dipertahankan di aplikasi. Saat pengguna mencoba mengakses sumber daya yang memerlukan autentikasi, token dikirim ke aplikasi dengan header otorisasi tambahan dalam bentuk Bearer token. Pendekatan ini menjadikan aplikasi tidak bergantung pada status. Dalam setiap permintaan berikutnya, token diteruskan dalam permintaan validasi sisi server. Token ini tidak dienkripsi; dikodekan. Di server, token didekodekan untuk mengakses informasinya. Untuk mengirim token pada permintaan berikutnya, simpan token di penyimpanan lokal browser. Menempatkan token di penyimpanan lokal browser dan mengambilnya dan menggunakannya sebagai token pembawa memberikan perlindungan terhadap serangan CSRF. Namun, jika aplikasi rentan terhadap injeksi skrip melalui XSS atau file JavaScript eksternal yang disusupi, penyerang cyber dapat mengambil nilai apa pun dari penyimpanan lokal dan mengirimkannya ke diri mereka sendiri. ASP.NET Core mengodekan semua output sisi server dari variabel secara default, mengurangi risiko XSS. Jika Anda mengambil alih perilaku ini dengan menggunakan Html.Raw atau kode kustom dengan input yang tidak tepercaya, Maka Anda dapat meningkatkan risiko XSS.
Jangan khawatir tentang kerentanan CSRF jika token disimpan di penyimpanan lokal browser. CSRF menjadi perhatian ketika token disimpan dalam cookie. Untuk informasi selengkapnya, lihat isu GitHub tentang sampel kode SPA SPA code sample adds two cookies.
Beberapa aplikasi yang dihosting di satu domain
Lingkungan hosting bersama rentan terhadap pembajakan sesi, serangan CSRF saat masuk, dan serangan lainnya.
Meskipun example1.contoso.net dan example2.contoso.net merupakan host yang berbeda, ada hubungan kepercayaan implisit antara host di *.contoso.net bawah domain. Hubungan kepercayaan implisit ini memungkinkan host yang berpotensi tidak tepercaya untuk memengaruhi cookie satu sama lain (kebijakan asal yang sama yang mengatur permintaan AJAX tidak selalu berlaku untuk cookie HTTP).
Serangan yang mengeksploitasi cookie tepercaya antara aplikasi yang dihosting di domain yang sama dapat dicegah dengan tidak berbagi domain. Saat setiap aplikasi dihosting di domainnya sendiri, tidak ada hubungan kepercayaan implisit cookie untuk dieksploitasi.
Mengambil header metadata
Peramban modern menyertakan header permintaan Fetch Metadata—yang terpenting Sec-Fetch-Site—dalam setiap permintaan.
Sec-Fetch-Site menjelaskan hubungan antara asal yang memulai permintaan dan asal yang diminta: same-origin mengidentifikasi permintaan yang dibuat situs itu sendiri, sementara same-site dan cross-site mengidentifikasi permintaan yang dimulai oleh asal lain. Header Origin memuat origin pemrakarsa dan berfungsi sebagai cadangan untuk browser yang mendahului Fetch Metadata.
Sec-Fetch-Site dan Origin adalah header permintaan terlarang: browser mengaturnya, dan JavaScript yang berjalan di halaman tidak dapat mengambil alih atau memalsukannya. Hal itu menjadikannya sinyal yang tepercaya untuk membedakan permintaan dari situs itu sendiri dengan permintaan lintas situs tanpa token yang diterbitkan server. Perlindungan CSRF otomatis yang disertakan dalam ASP.NET Core menggunakan sinyal ini untuk menolak posting formulir lintas situs yang tidak tepercaya secara eksplisit.
Perlindungan CSRF otomatis di ASP.NET Core
ASP.NET Core mengirimkan middleware perlindungan CSRF otomatis yang diaktifkan secara default di aplikasi yang dibangun dengan WebApplication.CreateBuilder. Tidak seperti sistem antiforgery berbasis token, middleware ini tidak mengeluarkan atau memvalidasi token. Sebaliknya, memeriksa Sec-Fetch-Site dan Originheader metadata Fetch serta mencatat hasil validasi untuk permintaan tersebut. Komponen yang memproses data formulir yang dikirim menegakkan keputusan tersebut dengan menolak pengiriman formulir dari origin berbeda yang tidak secara eksplisit dianggap tepercaya.
Untuk sebagian besar aplikasi, tidak diperlukan perubahan kode: permintaan browser dengan origin yang sama, metode HTTP yang aman, dan klien non-browser (curl, server-ke-server, aplikasi seluler) semuanya tetap berjalan tanpa terpengaruh. Middleware terutama memengaruhi aplikasi yang menerima pengiriman formulir lintas origin dari browser, seperti situs yang mengirimkan formulir ke API di origin yang berbeda. Skenario tersebut harus mengonfigurasi CORS untuk menetapkan origin tepercaya atau mengecualikan endpoint tersebut.
Middleware ini merupakan tambahan terhadap sistem antiforgery berbasis token. Kedua perlindungan tersebut hidup berdampingan dan keduanya dapat aktif pada titik akhir yang sama. Untuk membandingkan kapan masing-masing digunakan, lihat Interaksi dengan antiforgery berbasis token.
Cara kerjanya
Untuk setiap permintaan, middleware mengevaluasi rantai aturan singkat untuk mencapai putusan—diizinkan atau ditolak. Pemeriksaan berjalan secara berurutan, dan pertandingan pertama menang:
-
Metode HTTP aman selalu diizinkan.
GET, ,HEADOPTIONS, danTRACEpermintaan diteruskan. Ini mengikuti RFC 9110 §9.2.1 dan konsisten dengan aturan jangka panjang bahwa titik akhir tidak boleh mengubah status padaGET. -
Sec-Fetch-Site: same-originatauSec-Fetch-Site: nonediperbolehkan. Browser modern mengirimkanSec-Fetch-Sitesetiap permintaan.same-originmencakup navigasi dan pengambilan dalam aplikasi normal, dannonemencakup permintaan yang dimulai langsung oleh pengguna (mengetik URL, menggunakan bookmark). Ini adalah jalur kode yang paling umum—sebagian besar lalu lintas browser yang sah keluar di sini. - Asal tepercaya dari CORS diizinkan. Jika permintaan menyertakan header
Origindan kebijakan CORS endpoint yang telah ditetapkan memercayai origin tersebut, permintaan diizinkan. Middleware menyelesaikan kebijakan dengan cara yang sama seperti yang dilakukan middleware CORS: kebijakan per titik akhir dari[EnableCors("name")]pertama, lalu kebijakan default yang terdaftar denganAddDefaultPolicy. Lihat Mengizinkan klien lintas asal untuk batas penting pada aturan ini. - Nilai lain
Sec-Fetch-Siteditolak. JikaSec-Fetch-Siteberupacross-siteatausame-sitedan origin tidak tepercaya menurut CORS, permintaan ditolak. -
Tidak
Sec-Fetch-Site, tetapiOriginada: middleware membandingkanOrigindenganscheme://host[:port]yang dibuat dari permintaan. Jika cocok, permintaan diizinkan; jika tidak, itu ditolak. Ini adalah jalur cadangan untuk peramban yang lebih lama daripada spesifikasi Fetch Metadata (dirilis sekitar 2020). - Tanpa
Sec-Fetch-Sitedan tanpaOrigin: permintaan diizinkan. Peramban selalu mengirim setidaknya salah satu dari ini dalam permintaan tulis, jadi permintaan yang tidak menyertakan keduanya hampir pasti berasal dari klien non-peramban seperticurl, Postman, aplikasi seluler, atau pemanggil server-ke-server. CSRF adalah vektor serangan yang hanya terjadi di browser, sehingga permintaan ini tetap lolos.
Middleware mencatat keputusan ini pada request alih-alih mengakhiri request tersebut secara langsung. Untuk bagaimana dan kapan putusan yang ditolak berubah menjadi respons HTTP 400 Bad Request , lihat Validasi yang ditangguhkan.
Validasi yang ditangguhkan
Middleware tidak menolak permintaan dengan sendirinya. Sebaliknya, ia mencatat putusannya pada permintaan IAntiforgeryValidationFeature—fitur yang sama yang digunakan sistem antiforgery berbasis token—di mana putusan yang ditolak dicatat sebagai tidak valid. Permintaan terus diproses melalui pipeline. Putusan yang tidak valid menjadi HTTP 400 Bad Request hanya ketika komponen yang memproses data formulir mengamatinya. Penundaan ini sesuai dengan cara kerja sistem berbasis token: keputusan dihasilkan lebih awal, tetapi diterapkan saat formulir digunakan.
Komponen berikut membaca IAntiforgeryValidationFeature dan menolak permintaan dengan 400 - Bad Request ketika putusan yang direkam tidak valid:
- Aksi MVC dilindungi oleh anti-pemalsuan.
- Titik akhir API minimal yang mengikat parameter formulir.
- Blazor Titik akhir SSR.
- Kode apa pun yang membaca formulir permintaan secara langsung, yang berfungsi sebagai cadangan.
Setiap konsumen terlebih dahulu mengonfirmasi bahwa middleware antiforgery maupun CSRF benar-benar telah dijalankan sebelum memercayai hasil penilaian tersebut, sehingga pipeline tanpa salah satu dari middleware tersebut tidak akan menghasilkan penolakan keliru.
Konsekuensi dari model ini adalah bahwa endpoint yang tidak pernah membaca data formulir tetap dijalankan bahkan ketika hasil evaluasinya tidak valid. Misalnya, titik akhir JSON API yang mengikat isinya dari JSON, atau handler yang mengabaikan isi permintaan, tidak ditolak secara otomatis pada permintaan lintas asal. Keputusan tersebut masih dicatat pada IAntiforgeryValidationFeature untuk kode yang ingin memeriksanya, tetapi tidak ada yang menegakkannya. CSRF adalah vektor serangan berbasis formulir dancookie, sehingga endpoint yang tidak memproses formulir yang dikirimkan melalui browser umumnya tidak memerlukan penolakan ini. Titik akhir yang melakukan formulir proses—Razor Halaman, tampilan MVC, Blazor SSR, dan pengikatan formulir API Minimal—mendapatkan perlindungan secara otomatis.
Perilaku bawaan
Middleware didaftarkan secara otomatis oleh WebApplication.CreateBuilder dan berjalan setelah autentikasi dan otorisasi. Ini memvalidasi setiap permintaan menggunakan implementasi terdaftar ICsrfProtection , yang secara default menerapkan aturan yang dijelaskan dalam Cara kerjanya. Implementasi default dapat diganti; lihat Menyesuaikan: mengimplementasikan ICsrfProtection. Untuk menonaktifkan middleware sepenuhnya, lihat Menonaktifkan secara global.
Hasilnya adalah bahwa aplikasi minimal dengan titik akhir penanganan formulir seperti berikut ini sudah dilindungi:
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.MapPost("/widgets", ([FromForm] Widget w) =>
Results.Created($"/widgets/{w.Id}", w));
app.Run();
Browser yang membuat permintaan asal POST /widgets yang sama mencapai titik akhir secara normal. Browser pada https://attacker.example.com yang mengirimkan form yang sama ditolak dengan 400 - Bad Request saat endpoint mengikat form, sebelum badan handler dijalankan. Permintaan curl tanpa Sec-Fetch-Site atau Origin diizinkan.
Karena penolakan ditangguhkan hingga tahap pemrosesan oleh komponen yang mengonsumsi data formulir, endpoint yang tidak membaca data formulir—seperti API JSON yang mengikat body permintaannya dari JSON—tidak akan otomatis ditolak, bahkan pada permintaan lintas-origin. Hasilnya masih tercatat pada permintaan kode yang ingin memeriksanya.
Middleware terintegrasi dengan model antiforgery yang sudah ada:
-
Minimal API: Memanggil
.DisableAntiforgery()pada endpoint akan mengecualikan endpoint tersebut dari baik middleware berbasis token maupun middleware perlindungan CSRF. Metadata yang sama (IAntiforgeryMetadata { RequiresValidation = false }) diperiksa oleh keduanya. -
Kontroler dan aksi MVC:
[IgnoreAntiforgeryToken]juga mengecualikan endpoint dari kedua perlindungan tersebut.
Mengizinkan klien lintas asal
Skenario paling umum yang memerlukan tindakan adalah klien berbasis browser yang mengirimkan formulir lintas asal—misalnya, situs di https://app.contoso.com memposting formulir ke API di https://api.contoso.com. Kiriman formulir semacam itu ditolak secara bawaan karena Sec-Fetch-Site adalah same-site atau cross-site, bukan same-origin, dan konsumen formulir menegakkan keputusan tersebut dengan 400 - Bad Request.
Middleware CSRF tidak memperkenalkan daftar kepercayaannya sendiri. Ini menggunakan kembali kebijakan CORS yang sama yang diselesaikan middleware CORS untuk titik akhir: jika kebijakan tersebut memungkinkan permintaan Origin, middleware CSRF mencatat putusan yang diizinkan untuk permintaan tersebut.
Kebijakan dipilih per titik akhir dalam urutan ini:
-
[EnableCors("api")](MVC) atau.RequireCors("api")(Minimal API) → kebijakan bernama"api". - Tidak ada metadata CORS pada titik akhir → kebijakan default yang terdaftar dengan
AddDefaultPolicy. - Tidak ada kebijakan yang sesuai (kebijakan bernama tidak terdaftar, tidak ada kebijakan bawaan, atau
services.AddCors()tidak pernah dipanggil) → tidak ada kepercayaan yang berasal dari CORS. Middleware berlanjut keSec-Fetch-Sitedan aturan Origin-vs-Host.
Contoh minimal menggunakan kebijakan default dan titik akhir API Minimal:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddCors(options =>
{
options.AddDefaultPolicy(policy =>
policy.WithOrigins("https://app.contoso.com")
.AllowAnyHeader()
.AllowAnyMethod());
});
var app = builder.Build();
app.UseCors();
app.MapPost("/widgets", ([FromForm] Widget w) =>
Results.Created($"/widgets/{w.Id}", w));
app.Run();
Untuk kebijakan bernama pada satu titik akhir:
app.MapPost("/widgets", ([FromForm] Widget w) => Results.Created($"/widgets/{w.Id}", w))
.RequireCors("api");
Peringatan
AllowAnyOrigin sengaja tidak dianggap berlaku sebagai sinyal kepercayaan CSRF.
AllowAnyOrigin berarti "browser apa pun dapat membaca sumber daya ini," yang merupakan hal yang berbeda dari "origin apa pun boleh mengubah state atas nama pengguna." Memperlakukan AllowAnyOrigin sebagai tepercaya akan mengubah middleware ini menjadi no-op untuk penulisan lintas-origin. Aplikasi yang memerlukan kebijakan CORS baca-publik yang dikombinasikan dengan operasi tulis yang dilindungi CSRF harus secara eksplisit mencantumkan origin tulis tepercaya dengan WithOrigins atau mengecualikan endpoint tulis jika tidak mengandalkan autentikasi berbasis cookie.
[DisableCors] pada endpoint bukan pengecualian dari CSRF. Ini melewati langkah kepercayaan yang berasal dari CORS, dan permintaan tetap harus memenuhi Sec-Fetch-Site serta aturan Origin-vs-Host. Untuk mengecualikan diri dari perlindungan CSRF, lihat Mengecualikan titik akhir.
Untuk detail tentang mengonfigurasi CORS itu sendiri—AddCors, , AddDefaultPolicy, AddPolicyWithOrigins, dan API penyusun kebijakan lainnya—lihat Mengaktifkan Permintaan Lintas Asal (CORS) di ASP.NET Core.
Menonaktifkan titik akhir
Jika endpoint tidak dapat dijangkau melalui browser atau diamankan dengan mekanisme selain cookie, seperti token bearer atau kunci API, kecualikan endpoint tersebut secara individual alih-alih menonaktifkan middleware secara global.
API minimal — panggilan DisableAntiforgery pada titik akhir atau grup:
app.MapPost("/api/webhook", (WebhookPayload p) => Results.Accepted())
.DisableAntiforgery();
Kontroler MVC — terapkan [IgnoreAntiforgeryToken] pada aksi atau kontroler:
[ApiController]
[Route("api/[controller]")]
[IgnoreAntiforgeryToken]
public class WebhookController : ControllerBase
{
[HttpPost]
public IActionResult Post([FromBody] WebhookPayload payload) => Accepted();
}
Kedua pendekatan tersebut menambahkan IAntiforgeryMetadata { RequiresValidation = false } ke endpoint, sehingga middleware CSRF melewati validasi.
Peringatan
Menonaktifkan perlindungan CSRF pada titik akhir hanya boleh dilakukan ketika titik akhir tidak rentan terhadap serangan CSRF—misalnya, titik akhir yang tidak dapat dipanggil dari browser atau yang diamankan dengan autentikasi non-seperticookie token pembawa atau kunci API. Jangan nonaktifkan perlindungan CSRF pada titik akhir yang dapat diakses browser yang mengandalkan cookie untuk autentikasi.
Menonaktifkan secara global
Middleware dapat dinonaktifkan di seluruh aplikasi menggunakan DisableCsrfProtection kunci konfigurasi. Ini adalah solusi darurat—sebaiknya gunakan pengecualian untuk tiap endpoint.
Dalam appsettings.json:
{
"DisableCsrfProtection": true
}
Atau sebagai variabel lingkungan:
ASPNETCORE_DisableCsrfProtection=true
Ketika kunci ini diatur ke true, WebApplication melewati pendaftaran middleware di pipeline. Layanan ICsrfProtection tetap terdaftar, sehingga apa pun yang menyelesaikannya secara langsung terus berfungsi.
Peringatan
Middleware CSRF otomatis juga memenuhi persyaratan antiforgery untuk endpoint yang memerlukan validasi, bahkan saat aplikasi tidak memanggil app.UseAntiforgery(). Jika aplikasi bergantung pada antiforgery tetapi tidak memanggil app.UseAntiforgery(), menonaktifkan middleware CSRF secara global atau menjalankannya pada host yang tidak dibuat dengan WebApplication, yang menyebabkan middleware tidak disuntikkan, akan membuat endpoint tersebut tidak memiliki middleware antiforgery. Permintaan ke endpoint tersebut akan menimbulkan exception. Panggil app.UseAntiforgery() dalam konfigurasi tersebut.
Dukungan peramban
Sec-Fetch-Site didukung oleh semua versi browser berbasis Chromium saat ini, Firefox, dan Safari. Untuk tabel kompatibilitas otoritatif, lihat referensi MDN untuk Sec-Fetch-Site.
Browser lama yang sudah ada sebelum Fetch Metadata tidak mengirim Sec-Fetch-Site. Untuk klien tersebut, middleware beralih ke pembandingan header Origin dengan skema dan host permintaan. Peramban telah mengirim Origin pada permintaan penulisan lintas-asal selama bertahun-tahun, sehingga fallback ini mencakup hampir semua lalu lintas dari peramban lama.
Klien non-browser—curl, Postman, aplikasi seluler, pemanggil server-ke-server—biasanya tidak mengirim Sec-Fetch-Site maupun Origin. Permintaan tersebut diizinkan karena CSRF adalah vektor serangan khusus browser yang bergantung pada browser secara otomatis melampirkan kredensial sekitar seperti cookie. Klien non-browser yang ingin menyerang API tidak memerlukan CSRF; itu hanya dapat memanggil API secara langsung dengan kredensial apa pun yang dimilikinya.
Menyesuaikan: mengimplementasikan ICsrfProtection
Logika keputusan berada di belakang antarmuka satu metode:
namespace Microsoft.AspNetCore.Antiforgery;
public interface ICsrfProtection
{
ValueTask<CsrfProtectionResult> ValidateAsync(HttpContext context);
}
Untuk mengganti implementasi default, daftarkan singleton di DI. Karena kerangka kerja menggunakan TryAddSingleton, panggilan eksplisit AddSingleton mengambil alih default:
builder.Services.AddSingleton<ICsrfProtection, AllowlistCsrfProtection>();
Implementasi kustom berguna ketika model kepercayaan tidak sesuai dengan CORS—misalnya, ketika daftar izin tetap asal mitra lebih disukai, atau ketika aturan yang lebih ketat diperlukan:
using Microsoft.AspNetCore.Antiforgery;
using Microsoft.AspNetCore.Http;
public sealed class AllowlistCsrfProtection : ICsrfProtection
{
private static readonly HashSet<string> SafeMethods =
new(StringComparer.OrdinalIgnoreCase) { "GET", "HEAD", "OPTIONS", "TRACE" };
private static readonly HashSet<string> TrustedOrigins =
new(StringComparer.OrdinalIgnoreCase)
{
"https://app.contoso.com",
"https://admin.contoso.com",
};
public ValueTask<CsrfProtectionResult> ValidateAsync(HttpContext context)
{
if (SafeMethods.Contains(context.Request.Method))
{
return ValueTask.FromResult(CsrfProtectionResult.Allowed());
}
var origin = context.Request.Headers.Origin.ToString();
var allowed = !string.IsNullOrEmpty(origin) && TrustedOrigins.Contains(origin);
return ValueTask.FromResult(
allowed ? CsrfProtectionResult.Allowed() : CsrfProtectionResult.Denied());
}
}
Middleware masih menghormati .DisableAntiforgery() / [IgnoreAntiforgeryToken] terlepas dari implementasi mana yang terdaftar—penolakan ditangani oleh middleware itu sendiri sebelum ValidateAsync dipanggil.
Interaksi dengan antiforgery berbasis token
Dua pertahanan CSRF menargetkan lapisan yang berbeda dan dirancang untuk hidup berdampingan. Mereka juga berbagi fitur permintaan yang sama: merekam hasilnya pada IAntiforgeryValidationFeature, dan membentuk konsumen memberlakukan putusan apa pun yang ada.
| Aspek | Berbasis token AntiforgeryMiddleware |
Middleware untuk perlindungan CSRF otomatis |
|---|---|---|
| Pengenalan | ASP.NET Core 2.0+ | .NET 11 |
| Activation | Ikut serta melalui app.UseAntiforgery() (atau secara implisit oleh AddMvc / MapRazorPages / AddRazorComponents) |
Disuntikkan secara otomatis oleh WebApplication.CreateBuilder |
| Memvalidasi | Token yang disinkronkan (bidang formulir + pasangan cookie) |
Sec-Fetch-Site
/
Origin Header |
| Requires | ASP.NET Core Gambaran Umum Perlindungan Data untuk enkripsi token | Tidak ada token, tidak ada status |
| Cakupan peramban | Semua browser yang mengirim cookie | Semua browser modern; Origin opsi cadangan untuk browser lama |
| Penolakan per titik akhir | .DisableAntiforgery() / [IgnoreAntiforgeryToken] |
Sama — keduanya menghormati metadata yang sama |
Middleware berbasis token secara khusus melindungi dari pola serangan CSRF klasik di mana situs berbahaya memicu formulir POST ke situs yang rentan menggunakan cookie sekitar pengguna. Middleware CSRF otomatis mengatasi ancaman yang sama di lapisan HTTP menggunakan metadata yang disediakan browser. Keduanya dapat aktif pada titik akhir yang sama, dan banyak aplikasi akan mendapat manfaat dari pertahanan secara mendalam:
- Razor Aplikasi Pages, MVC, dan Blazor SSR yang sudah menggunakan sistem token mendapatkan pemeriksaan berbasis header yang berjalan sebelum validasi token, tanpa mengubah alur token.
-
Aplikasi Minimal API yang mengikat data formulir secara default mendapatkan perilaku yang berguna tanpa perlu memanggil
app.UseAntiforgery()atau meneruskanIAntiforgeryke endpoint. - API yang dipanggil dari SPA lintas-origin dapat mengandalkan middleware ini yang dikombinasikan dengan allowlist CORS, dan sepenuhnya melewati sistem token jika API tidak pernah menyajikan formulir HTML.
Middleware CSRF otomatis menggantikan sistem berbasis token dalam banyak skenario, karena keduanya melindungi titik akhir penanganan formulir yang sama. Pertahankan sistem berbasis token saat:
- Aplikasi harus mendukung browser yang tidak mengirim
Sec-Fetch-Site. Lihat Dukungan browser. - Aplikasi ini menggunakan IAntiforgeryAdditionalDataProvider untuk melakukan perjalanan pulang pergi data tambahan di dalam token.
- Tinjauan keamanan atau persyaratan kepatuhan menentukan pertahanan token sebagai lapisan independen.
Untuk detail tentang sistem berbasis token, termasuk integrasi formulir, alur AJAX, konfigurasi melalui AntiforgeryOptions, dan IAntiforgery API, lihat Antiforgery di ASP.NET Core.
Validasi token lebih diutamakan
Saat aplikasi memanggil app.UseAntiforgery(), middleware berbasis token dijalankan setelah middleware CSRF otomatis. Middleware token menghapus keputusan apa pun yang dicatat oleh middleware CSRF dan menggantinya dengan hasil validasi token. Hasil token bersifat otoritatif:
- Permintaan yang ditandai tidak valid oleh middleware CSRF menjadi valid jika menyertakan token yang valid.
- Sebuah permintaan yang diizinkan oleh middleware CSRF dianggap tidak valid jika tokennya hilang atau tidak valid.
Urutan ini berarti aplikasi yang menggunakan sistem token tetap mendapatkan perilaku end-to-end yang sama seperti sebelum middleware otomatis diterapkan, sedangkan aplikasi yang tidak menggunakan token akan mengikuti keputusan middleware CSRF.
Blazor perenderan statis di sisi server
Blazor Titik akhir penyajian sisi server statis (SSR) berpartisipasi dalam model yang ditangguhkan yang sama. Endpoint Razor Komponen memercayai hasil penilaian yang dicatat pada IAntiforgeryValidationFeature oleh middleware upstream dan hanya mengembalikan 400 - Bad Request untuk pengiriman formulir jika hasil penilaian tersebut tidak valid. Titik akhir tidak lagi memvalidasi permintaan itu sendiri.
Perilaku tergantung pada middleware mana yang dijalankan:
- Aplikasi yang memanggil
app.UseAntiforgery()tidak berubah. Middleware berbasis token memverifikasi setiap permintaan, dan token antipemalsuan dibuat untuk formulir yang ditampilkan seperti sebelumnya. - Aplikasi yang tidak memanggil
app.UseAntiforgery()dilindungi oleh middleware CSRF otomatis sebagai gantinya. Dalam konfigurasi tersebut, endpoint tidak membuat token antiforgery karena tidak ada middleware untuk memvalidasi token pada permintaan berikutnya.
Ini adalah perubahan perilaku untuk SSR statis yang sebelumnya menghapus app.UseAntiforgery(): kini elemen tersebut dilindungi oleh middleware CSRF alih-alih dibiarkan tanpa perlindungan, dan tidak lagi menghasilkan token antiforgery. Untuk panduan migrasi, lihat Migrasi dari ASP.NET Core di .NET 10 ke ASP.NET Core di .NET 11. Untuk pemberitahuan resmi tentang perubahan yang menyebabkan ketidakcocokan, lihat Blazor perenderan sisi server menyerahkan validasi antipemalsuan kepada middleware.
Troubleshooting
Gejala: Permintaan asal yang sama dari browser berhasil, tetapi posting formulir lintas asal kembali 400 - Bad Request tanpa isi.
Menyebabkan: Middleware CSRF merekam putusan yang tidak valid untuk permintaan lintas asal, dan komponen pemrosesan formulir—seperti tindakan MVC, pengikatan formulir API Minimal, atau Blazor posting formulir SSR—memberlakukan putusan tersebut dengan 400 - Bad Request. Ini adalah perilaku default yang diharapkan untuk titik akhir yang memproses formulir.
Resolusi: Pilih salah satu hal berikut, tergantung pada skenarionya:
- Jika asal panggilan diketahui dan tepercaya, izinkan melalui CORS.
- Jika endpoint tidak dapat diakses melalui browser atau menggunakan autentikasi non-cookie, kecualikan dengan
.DisableAntiforgery()atau[IgnoreAntiforgeryToken]. - Jika seluruh aplikasi perlu tidak ikut serta (misalnya, selama masa migrasi), nonaktifkan secara global.
Diagnosis: Middleware tersebut mencatat setiap verdict yang tidak valid pada level Debug dalam kategori Microsoft.AspNetCore.Antiforgery.CsrfProtectionMiddleware dengan nama peristiwa CsrfValidationFailed. Aktifkan Debug pengelogan untuk kategori tersebut di appsettings.Development.json:
{
"Logging": {
"LogLevel": {
"Microsoft.AspNetCore.Antiforgery.CsrfProtectionMiddleware": "Debug"
}
}
}
Putusan yang direkam kemudian muncul di log sebagai:
dbug: Microsoft.AspNetCore.Antiforgery.CsrfProtectionMiddleware[1]
Cross-origin CSRF protection marked request POST /widgets from origin 'https://attacker.example.com' as invalid.
Mereprodusi secara lokal: Gunakan curl dengan header eksplisit Origin untuk mensimulasikan permintaan browser lintas asal terhadap titik akhir formulir:
curl -i -X POST https://localhost:{PORT}/widgets \
-H "Origin: https://attacker.example.com" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "name=test"
Ganti {PORT} dengan port HTTPS lokal aplikasi.
400 - Bad Request diamati karena titik akhir mengikat formulir, yang memberlakukan putusan yang direkam. Titik akhir non-formulir mengembalikan respons normalnya karena tidak ada yang membaca putusan. Tanpa header Origin, permintaan yang sama diizinkan karena curl juga tidak mengirim Sec-Fetch-Site, dan permintaan tanpa kedua header tersebut dianggap sebagai klien non-browser.
Sistem antiforgery berbasis token yang dijelaskan di sisa artikel ini mendahului middleware ini dan tetap tersedia. Untuk sebagian besar aplikasi, perlindungan otomatis sudah cukup dengan sendirinya. Untuk panduan tentang kapan harus menjaga sistem berbasis token dan cara bermigrasi, lihat Migrasi dari ASP.NET Core di .NET 10 ke ASP.NET Core di .NET 11.
Anti-Pemalsuan dalam ASP.NET Core
Peringatan
ASP.NET Core mengimplementasikan antiforgery menggunakan ASP.NET Core Data Protection. Tumpukan perlindungan data harus dikonfigurasi untuk bekerja di farm server. Untuk informasi selengkapnya, lihat Mengonfigurasi perlindungan data.
Layanan anti-pemalsuan didaftarkan dalam kontainer injeksi dependensi saat salah satu API berikut dipanggil di Program.cs:
Catatan
Mendaftarkan layanan tidak menambahkan middleware Antiforgery ke alur pemrosesan permintaan. MVC dan Razor Pages memvalidasi token dengan filter bawaan, sehingga tidak memerlukan middleware.
Blazor dan API Minimal memerlukan panggilan eksplisit ke UseAntiforgery dalam Program.cs, yang ada secara default dalam Blazor Web App templat proyek. Untuk informasi selengkapnya, lihat ASP.NET Core Blazor autentikasi dan otorisasi dan Antiforgery dengan API Minimal.
Untuk informasi selengkapnya, lihat Antiforgery dengan Minimal APIs.
FormTagHelper menyuntikkan token anti-pemalsuan ke dalam elemen formulir HTML. Markup berikut dalam Razor file secara otomatis menghasilkan token antiforgery:
<form method="post">
<!-- ... -->
</form>
Demikian pula, IHtmlHelper.BeginForm menghasilkan token antiforgery secara default jika metode formulir bukan GET.
Pembuatan otomatis token antiforgery untuk elemen formulir HTML terjadi ketika <form> tag berisi method="post" atribut dan salah satu dari yang berikut ini benar:
- Atribut tindakan kosong (
action=""). - Atribut tindakan tidak disediakan (
<form method="post">).
Pembuatan token antiforgeri otomatis untuk elemen formulir HTML dapat dinonaktifkan:
Nonaktifkan token antiforgery secara eksplisit dengan
asp-antiforgeryatribut :<form method="post" asp-antiforgery="false"> <!-- ... --> </form>Elemen formulir ditolak dari Pembantu Tag dengan menggunakan simbol penolakan Pembantu Tag ! :
<!form method="post"> <!-- ... --> </!form>Hapus
FormTagHelperdari tampilan.FormTagHelperdapat dihapus dari tampilan dengan menambahkan direktif berikut ke Razor tampilan:@removeTagHelper Microsoft.AspNetCore.Mvc.TagHelpers.FormTagHelper, Microsoft.AspNetCore.Mvc.TagHelpers
Catatan
Razor Halaman secara otomatis dilindungi dari XSRF/CSRF. Untuk informasi selengkapnya, lihat XSRF/CSRF dan Razor Pages.
Pendekatan paling umum untuk melindungi dari serangan CSRF adalah menggunakan Pola Token Sinkronisasi (STP). STP digunakan saat pengguna meminta halaman dengan data formulir:
- Server mengirim token yang terkait dengan identitas pengguna saat ini ke klien.
- Klien mengirim kembali token ke server untuk verifikasi.
- Jika server menerima token yang tidak cocok dengan identitas pengguna yang diautentikasi, permintaan akan ditolak.
Token unik dan tidak dapat diprediksi. Token juga dapat digunakan untuk memastikan urutan yang tepat dari serangkaian permintaan (misalnya, memastikan urutan permintaan: halaman 1 > halaman 2 > halaman 3). Semua formulir dalam templat ASP.NET Core MVC dan Razor Pages menghasilkan token antiforgery. Contoh tampilan berikut ini menghasilkan token anti-pemalsuan:
<form asp-action="Index" asp-controller="Home" method="post">
<!-- ... -->
</form>
@using (Html.BeginForm("Index", "Home"))
{
<!-- ... -->
}
Secara eksplisit tambahkan token antiforgery ke elemen <form> tanpa menggunakan Tag Helpers dengan HTML helper @Html.AntiForgeryToken.
<form asp-action="Index" asp-controller="Home" method="post">
@Html.AntiForgeryToken()
<!-- ... -->
</form>
Dalam setiap kasus sebelumnya, ASP.NET Core menambahkan bidang formulir tersembunyi yang mirip dengan contoh berikut:
<input name="__RequestVerificationToken" type="hidden" value="CfDJ8NrAkS ... s2-m9Yw">
ASP.NET Core mencakup tiga filter untuk menangani token antiforgery.
Penangkal Pemalsuan dengan AddControllers
AddControllers Panggilan tidak mengaktifkan token antiforgery. AddControllersWithViews harus dipanggil agar memiliki dukungan token antiforgery bawaan.
Beberapa tab browser dan Pola Token Sinkronisasi
Beberapa tab yang masuk sebagai pengguna yang berbeda, atau yang masuk sebagai anonim, tidak didukung.
Mengonfigurasi fitur anti-pemalsuan dengan AntiforgeryOptions
Kustomisasi AntiforgeryOptions dalam file aplikasi Program :
builder.Services.AddAntiforgery(options =>
{
// Set Cookie properties using CookieBuilder properties†.
options.FormFieldName = "AntiforgeryFieldname";
options.HeaderName = "X-CSRF-TOKEN-HEADERNAME";
options.SuppressXFrameOptionsHeader = false;
});
Atur properti antiforgery cookie menggunakan properti kelas CookieBuilder, seperti yang ditunjukkan dalam tabel berikut.
| Opsi | Deskripsi |
|---|---|
| Cookie | Menentukan pengaturan yang digunakan untuk membuat cookie antiforgery. |
| FormFieldName | Nama kolom formulir tersembunyi yang digunakan oleh sistem antiforgery untuk memproses token antiforgery dalam tampilan. |
| HeaderName | Nama header yang digunakan oleh sistem anti-pemalsuan. Jika null, sistem hanya mempertimbangkan data formulir. |
| SuppressXFrameOptionsHeader | Menentukan apakah akan mengabaikan pembuatan header X-Frame-Options. Secara default, header dihasilkan dengan nilai "SAMEORIGIN". Bawaan ke false. |
Beberapa browser tidak mengizinkan titik akhir yang tidak aman untuk mengatur cookie dengan flag 'secure' atau menimpa cookie yang flag 'secure'-nya sudah diatur (untuk informasi selengkapnya, lihat Menyarankan untuk tidak memodifikasi cookie 'secure' dari asal yang tidak aman). Karena mencampur titik akhir yang aman dan tidak aman adalah skenario umum dalam aplikasi, ASP.NET Core melonggarkan pembatasan pada kebijakan aman pada beberapa cookie, seperti antiforgery cookie, dengan mengatur cookie dari SecurePolicy ke CookieSecurePolicy.None. Bahkan jika pengguna berbahaya mencuri antiforgery cookie, mereka juga harus mencuri token antiforgery yang biasanya dikirim melalui bidang formulir (lebih umum) atau header permintaan terpisah (kurang umum) ditambah autentikasi cookie.
Cookies terkait dengan autentikasi atau otorisasi menggunakan kebijakan yang lebih kuat daripada CookieSecurePolicy.None.
Secara opsional, Anda dapat mengamankan antiforgery cookie di lingkungan yang tidak menggunakan Development dengan menggunakan Secure Sockets Layer (SSL) melalui HTTPS saja, dengan pengaturan properti berikut AntiforgeryOptions.Cookie dalam file aplikasi Program :
if (!builder.Environment.IsDevelopment())
{
builder.Services.AddAntiforgery(o =>
{
o.Cookie.SecurePolicy = CookieSecurePolicy.Always;
});
}
Untuk informasi selengkapnya, lihat CookieAuthenticationOptions .
Hasilkan token anti-pemalsuan dengan IAntiforgery
IAntiforgery menyediakan API untuk mengonfigurasi fitur antiforgery.
IAntiforgery dapat diminta dalam Program.cs menggunakan WebApplication.Services. Contoh berikut ini menggunakan middleware dari halaman utama aplikasi untuk menghasilkan token antiforgery dan mengirimkannya dalam respons sebagai cookie:
app.UseRouting();
app.UseAuthorization();
var antiforgery = app.Services.GetRequiredService<IAntiforgery>();
app.Use((context, next) =>
{
var requestPath = context.Request.Path.Value;
if (string.Equals(requestPath, "/", StringComparison.OrdinalIgnoreCase)
|| string.Equals(requestPath, "/index.html", StringComparison.OrdinalIgnoreCase))
{
var tokenSet = antiforgery.GetAndStoreTokens(context);
context.Response.Cookies.Append("XSRF-TOKEN", tokenSet.RequestToken!,
new CookieOptions { HttpOnly = false });
}
return next(context);
});
Contoh sebelumnya menetapkan sebuah cookie yang diberi nama XSRF-TOKEN. Klien dapat membaca ini cookie dan memberikan nilainya sebagai header yang dilampirkan ke permintaan AJAX. Misalnya, Angular menyertakan perlindungan XSRF bawaan yang secara default membaca sebuah elemen bernama cookieXSRF-TOKEN.
Memerlukan validasi pencegahan pemalsuan
Filter aksi ValidateAntiForgeryToken dapat diterapkan ke aksi individu, kontroler, atau secara global. Permintaan yang dibuat untuk tindakan yang menerapkan filter ini diblokir kecuali permintaan menyertakan token antiforgery yang valid:
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Index()
{
// ...
return RedirectToAction();
}
Atribut ValidateAntiForgeryToken memerlukan token untuk permintaan ke metode tindakan yang ditandainya, termasuk permintaan HTTP GET. Jika atribut ValidateAntiForgeryToken diterapkan di seluruh pengontrol aplikasi, atribut tersebut dapat ditimpa dengan atribut IgnoreAntiforgeryToken.
Memvalidasi secara otomatis token antiforgery hanya untuk metode HTTP yang dianggap tidak aman.
Alih-alih menerapkan atribut ValidateAntiForgeryToken secara luas dan kemudian menimpanya dengan atribut IgnoreAntiforgeryToken, atribut AutoValidateAntiforgeryToken dapat digunakan. Atribut ini berfungsi secara identik dengan ValidateAntiForgeryToken atribut , kecuali bahwa atribut ini tidak memerlukan token untuk permintaan yang dibuat menggunakan metode HTTP berikut:
- DAPATKAN
- Kepala
- OPSI
- TRACE
Sebaiknya gunakan AutoValidateAntiforgeryToken secara luas untuk skenario non-API. Atribut ini memastikan tindakan POST dilindungi secara default. Alternatifnya adalah mengabaikan token antiforgery secara default, kecuali ValidateAntiForgeryToken diterapkan ke metode tindakan individual. Dalam skenario ini, lebih mungkin metode tindakan POST dibiarkan tidak terlindungi secara tidak sengaja, membuat aplikasi rentan terhadap serangan CSRF. Semua POS harus mengirim token antiforgery.
API tidak memiliki mekanisme otomatis untuk mengirimkan bagian dari token yang bukan cookie. Implementasi mungkin tergantung pada implementasi kode klien. Beberapa contoh ditunjukkan di bawah ini:
Contoh pada tingkat kelas:
[AutoValidateAntiforgeryToken]
public class HomeController : Controller
Contoh global:
builder.Services.AddControllersWithViews(options =>
{
options.Filters.Add(new AutoValidateAntiforgeryTokenAttribute());
});
Mengambil alih atribut antiforgery global atau pengontrol
Filter IgnoreAntiforgeryToken digunakan untuk menghilangkan kebutuhan token antiforgery untuk tindakan tertentu (atau pengontrol). Ketika diterapkan, filter ini akan mengesampingkan filter ValidateAntiForgeryToken dan AutoValidateAntiforgeryToken yang ditentukan pada tingkat yang lebih tinggi (secara global atau pada pengontrol).
[IgnoreAntiforgeryToken]
public IActionResult IndexOverride()
{
// ...
return RedirectToAction();
}
Penyegaran token setelah autentikasi
Token harus di-refresh setelah pengguna diautentikasi dengan mengalihkan pengguna ke halaman tampilan atau Razor Halaman.
JavaScript, AJAX, dan SPAs
Dalam aplikasi tradisional berbasis HTML, token antiforgery dikirimkan ke server menggunakan kolom formulir tersembunyi. Di aplikasi dan SPAs berbasis JavaScript modern, banyak permintaan dibuat secara terprogram. Permintaan AJAX ini dapat menggunakan teknik lain, seperti header permintaan atau cookie, untuk mengirim token.
Jika cookie digunakan untuk menyimpan token autentikasi dan untuk mengautentikasi permintaan API di server, CSRF adalah masalah potensial. Jika penyimpanan lokal digunakan untuk menyimpan token, kerentanan CSRF mungkin dimitigasi karena nilai dari penyimpanan lokal tidak dikirim secara otomatis ke server dengan setiap permintaan. Menggunakan penyimpanan lokal untuk menyimpan token antiforgery pada klien dan mengirim token sebagai header permintaan adalah pendekatan yang direkomendasikan.
Blazor
Untuk informasi selengkapnya, lihat ASP.NET Core Blazor autentikasi dan otorisasi.
JavaScript
Dengan menggunakan JavaScript pada tampilan, token dapat dibuat menggunakan layanan dari dalam tampilan tersebut. IAntiforgery Masukkan layanan ke dalam tampilan dan panggil GetAndStoreTokens:
@inject Microsoft.AspNetCore.Antiforgery.IAntiforgery Antiforgery
@{
ViewData["Title"] = "JavaScript";
var requestToken = Antiforgery.GetAndStoreTokens(Context).RequestToken;
}
<input id="RequestVerificationToken" type="hidden" value="@requestToken" />
<button id="button" class="btn btn-primary">Submit with Token</button>
<div id="result" class="mt-2"></div>
@section Scripts {
<script>
document.addEventListener("DOMContentLoaded", () => {
const resultElement = document.getElementById("result");
document.getElementById("button").addEventListener("click", async () => {
const response = await fetch("@Url.Action("FetchEndpoint")", {
method: "POST",
headers: {
RequestVerificationToken:
document.getElementById("RequestVerificationToken").value
}
});
if (response.ok) {
resultElement.innerText = await response.text();
} else {
resultElement.innerText = `Request Failed: ${response.status}`
}
});
});
</script>
}
Contoh sebelumnya menggunakan JavaScript untuk membaca nilai bidang tersembunyi untuk header AJAX POST.
Pendekatan ini menghilangkan kebutuhan untuk berurusan langsung dengan pengaturan cookie dari server atau membacanya dari klien. Namun, jika menyuntikkan layanan IAntiforgery tidak memungkinkan, gunakan JavaScript untuk mengakses token dalam cookie.
- Akses token dalam permintaan tambahan ke server, biasanya
same-origin. - Gunakan konten dari cookie untuk membuat header dengan nilai token.
Dengan asumsi skrip mengirimkan token di header permintaan yang disebutkan X-XSRF-TOKEN, konfigurasikan layanan antiforgery untuk mencari header X-XSRF-TOKEN.
builder.Services.AddAntiforgery(options => options.HeaderName = "X-XSRF-TOKEN");
Contoh berikut menambahkan titik akhir terproteksi yang menulis token permintaan ke JavaScript yang dapat cookiedibaca :
app.UseAuthorization();
app.MapGet("antiforgery/token", (IAntiforgery forgeryService, HttpContext context) =>
{
var tokens = forgeryService.GetAndStoreTokens(context);
context.Response.Cookies.Append("XSRF-TOKEN", tokens.RequestToken!,
new CookieOptions { HttpOnly = false });
return Results.Ok();
}).RequireAuthorization();
Contoh berikut menggunakan JavaScript untuk membuat permintaan AJAX untuk mendapatkan token dan membuat permintaan lain dengan header yang sesuai:
var response = await fetch("/antiforgery/token", {
method: "GET",
headers: { "Authorization": authorizationToken }
});
if (response.ok) {
// https://developer.mozilla.org/docs/web/api/document/cookie
const xsrfToken = document.cookie
.split("; ")
.find(row => row.startsWith("XSRF-TOKEN="))
.split("=")[1];
response = await fetch("/JavaScript/FetchEndpoint", {
method: "POST",
headers: { "X-XSRF-TOKEN": xsrfToken, "Authorization": authorizationToken }
});
if (response.ok) {
resultElement.innerText = await response.text();
} else {
resultElement.innerText = `Request Failed: ${response.status}`
}
} else {
resultElement.innerText = `Request Failed: ${response.status}`
}
Catatan
Ketika token antiforgery disediakan di header permintaan dan dalam payload formulir, hanya token di header yang divalidasi.
Pencegahan Pemalsuan dengan API Minimal
Panggil AddAntiforgery untuk mendaftarkan layanan antiforgery di DI, dan UseAntiforgery untuk menambahkan Middleware Antiforgery ke alur pemrosesan permintaan. Token antiforgery digunakan untuk mengurangi serangan pemalsuan permintaan lintas situs.
var builder = WebApplication.CreateBuilder();
builder.Services.AddAntiforgery();
var app = builder.Build();
app.UseAntiforgery();
app.MapGet("/", () => "Hello World!");
app.Run();
Middleware pencegahan pemalsuan
- Apakah tidak menghentikan pelaksanaan sisa dari alur permintaan.
- Mengatur IAntiforgeryValidationFeature dalam HttpContext.Features permintaan saat ini.
Token antiforgery hanya divalidasi jika:
- Titik akhir berisi metadata yang menerapkan IAntiforgeryMetadata untuk
RequiresValidation=true. - Metode HTTP yang terkait dengan titik akhir adalah metode HTTP yang relevan dari jenis POST, PUT, atau PATCH.
- Permintaan dikaitkan dengan titik akhir yang valid.
Middleware antiforgery tidak mempersingkat sirkuit alur permintaan. Kode titik akhir selalu berjalan, bahkan jika validasi token gagal. Untuk mengamati hasil validasi token, tangani IAntiforgeryValidationFeature dari HttpContext.Features dan periksa properti IsValid atau properti Error untuk detail kegagalan. Pendekatan ini berguna ketika titik akhir memerlukan penanganan kustom untuk validasi antiforgery yang gagal.
Catatan: Saat diaktifkan secara manual, middleware antiforgery harus berjalan setelah middleware autentikasi dan otorisasi untuk mencegah membaca data formulir saat pengguna tidak diautentikasi.
Secara default, API Minimal yang menerima data formulir memerlukan validasi token antiforgery dan gagal sebelum menjalankan kode aplikasi jika validasi antiforgery tidak berhasil.
Pertimbangkan metode berikut GenerateForm :
public static string GenerateForm(string action,
AntiforgeryTokenSet token, bool UseToken=true)
{
string tokenInput = "";
if (UseToken)
{
tokenInput = $@"<input name=""{token.FormFieldName}""
type=""hidden"" value=""{token.RequestToken}"" />";
}
return $@"
<html><body>
<form action=""{action}"" method=""POST"" enctype=""multipart/form-data"">
{tokenInput}
<input type=""text"" name=""name"" />
<input type=""date"" name=""dueDate"" />
<input type=""checkbox"" name=""isCompleted"" />
<input type=""submit"" />
</form>
</body></html>
";
}
Kode sebelumnya memiliki tiga argumen, tindakan, token antiforgery, dan bool menunjukkan apakah token harus digunakan.
Pertimbangkan sampel berikut:
using Microsoft.AspNetCore.Antiforgery;
using Microsoft.AspNetCore.Mvc;
var builder = WebApplication.CreateBuilder();
builder.Services.AddAntiforgery();
var app = builder.Build();
app.UseAntiforgery();
// Pass token
app.MapGet("/", (HttpContext context, IAntiforgery antiforgery) =>
{
var token = antiforgery.GetAndStoreTokens(context);
return Results.Content(MyHtml.GenerateForm("/todo", token), "text/html");
});
// Don't pass a token, fails
app.MapGet("/SkipToken", (HttpContext context, IAntiforgery antiforgery) =>
{
var token = antiforgery.GetAndStoreTokens(context);
return Results.Content(MyHtml.GenerateForm("/todo",token, false ), "text/html");
});
// Post to /todo2. DisableAntiforgery on that endpoint so no token needed.
app.MapGet("/DisableAntiforgery", (HttpContext context, IAntiforgery antiforgery) =>
{
var token = antiforgery.GetAndStoreTokens(context);
return Results.Content(MyHtml.GenerateForm("/todo2", token, false), "text/html");
});
app.MapPost("/todo", ([FromForm] Todo todo) => Results.Ok(todo));
app.MapPost("/todo2", ([FromForm] Todo todo) => Results.Ok(todo))
.DisableAntiforgery();
app.Run();
class Todo
{
public required string Name { get; set; }
public bool IsCompleted { get; set; }
public DateTime DueDate { get; set; }
}
public static class MyHtml
{
public static string GenerateForm(string action,
AntiforgeryTokenSet token, bool UseToken=true)
{
string tokenInput = "";
if (UseToken)
{
tokenInput = $@"<input name=""{token.FormFieldName}""
type=""hidden"" value=""{token.RequestToken}"" />";
}
return $@"
<html><body>
<form action=""{action}"" method=""POST"" enctype=""multipart/form-data"">
{tokenInput}
<input type=""text"" name=""name"" />
<input type=""date"" name=""dueDate"" />
<input type=""checkbox"" name=""isCompleted"" />
<input type=""submit"" />
</form>
</body></html>
";
}
}
Dalam kode sebelumnya, memposting ke:
-
/todomemerlukan token antiforgery yang valid. -
/todo2tidak memerlukan token antiforgery yang valid karena DisableAntiforgery dipanggil.
app.MapPost("/todo", ([FromForm] Todo todo) => Results.Ok(todo));
app.MapPost("/todo2", ([FromForm] Todo todo) => Results.Ok(todo))
.DisableAntiforgery();
Peringatan
Memanggil .DisableAntiforgery() menonaktifkan perlindungan pemalsuan permintaan lintas situs (CSRF) untuk titik akhir. Ini hanya boleh digunakan ketika titik akhir tidak rentan terhadap serangan CSRF, seperti:
- Titik akhir yang tidak dapat dipanggil dari browser (misalnya, API internal)
- Titik akhir diamankan dengan autentikasi non-berbasiscookie (misalnya, token pembawa atau kunci API)
- Titik akhir internal atau infrastruktur yang tidak bergantung pada cookie pengguna
Jangan nonaktifkan validasi antiforgery untuk titik akhir yang dapat diakses browser yang mengandalkan cookie untuk autentikasi atau yang memproses data formulir yang dikirim pengguna, karena ini mengekspos aplikasi Anda ke serangan CSRF.
Sebuah POST ke:
-
/tododari formulir yang dihasilkan oleh endpoint/berhasil karena token antiforgery valid. -
/tododari formulir yang dihasilkan oleh/SkipTokengagal karena antiforgery tidak disertakan. -
/todo2dari formulir yang dihasilkan oleh/DisableAntiforgeryendpoint berhasil karena antiforgery tidak diperlukan.
app.MapPost("/todo", ([FromForm] Todo todo) => Results.Ok(todo));
app.MapPost("/todo2", ([FromForm] Todo todo) => Results.Ok(todo))
.DisableAntiforgery();
Ketika formulir dikirimkan tanpa token antiforgery yang valid:
- Di lingkungan
Development, sebuah pengecualian terjadi. - Di lingkungan
Production, sebuah pesan dicatat.
Batasan metode HTTP dan interaksi HttpMethodOverrideMiddleware
Untuk jalur antiforgery berbasis middleware, AntiforgeryMiddleware dan UseAntiforgery() validasi token antiforgery hanya untuk permintaan HTTP POST, PUT, dan PATCH . Metode HTTP lainnya, seperti DELETE, tidak divalidasi secara otomatis.
Untuk memvalidasi token antiforgery untuk metode HTTP lainnya, selesaikan IAntiforgery dari DI dan panggil ValidateRequestAsync atau IsRequestValidAsync secara eksplisit:
app.MapDelete("/item/{id}", async (int id, IAntiforgery antiforgery, HttpContext context) =>
{
await antiforgery.ValidateRequestAsync(context);
// Process the DELETE request
});
Peringatan
Ketika HttpMethodOverrideMiddleware dikonfigurasi dengan FormFieldName (mode bidang formulir) dan ditempatkan sebelum AntiforgeryMiddleware, permintaan POST dapat dioverride menjadi DELETE (atau metode lain yang tidak tervalidasi). Karena AntiforgeryMiddleware hanya memvalidasi POST, PUT, dan PATCH, permintaan yang dioverride tidak menjalani validasi antiforgery.
Untuk melindungi titik akhir ini:
- Sebaiknya tempatkan
HttpMethodOverrideMiddlewaresetelah validasi antiforgery jika pipeline Anda memungkinkannya. - Hindari penimpaan isian formulir untuk endpoint yang mengandalkan validasi anti-pemalsuan.
- Jika override pada field formulir perlu dijalankan terlebih dahulu, validasi token antiforgery secara eksplisit menggunakan
IAntiforgery.ValidateRequestAsync.
Untuk detail konfigurasi, lihat ASP.NET Core middleware.
Autentikasi Windows dan kuki anti-pemalsuan
Saat menggunakan Autentikasi Windows, titik akhir aplikasi harus dilindungi dari serangan CSRF dengan cara yang sama seperti yang dilakukan untuk cookie. Browser secara implisit mengirim konteks autentikasi ke server dan titik akhir perlu dilindungi dari serangan CSRF.
Perluas fitur anti-pemalsuan
Jenis ini IAntiforgeryAdditionalDataProvider memungkinkan pengembang untuk memperpanjang fungsi sistem anti-CSRF dengan memutar alihkan data tambahan di setiap token. Metode GetAdditionalData ini dipanggil setiap kali token bidang dihasilkan, dan nilai pengembalian disematkan dalam token yang dihasilkan. Pelaksana dapat mengembalikan tanda waktu, nonce, atau nilai lain lalu memanggil ValidateAdditionalData untuk memvalidasi data ini saat token divalidasi. Nama pengguna klien sudah disematkan dalam token yang dihasilkan, sehingga tidak perlu menyertakan informasi ini. Jika token menyertakan data tambahan tetapi tidak IAntiForgeryAdditionalDataProvider dikonfigurasi, data tambahan tidak divalidasi.
Sumber Daya Tambahan:
Pemalsuan permintaan lintas situs (juga dikenal sebagai XSRF atau CSRF) adalah serangan terhadap aplikasi yang dihosting web di mana aplikasi web berbahaya dapat memengaruhi interaksi antara browser klien dan aplikasi web yang mempercayai browser tersebut. Serangan ini dimungkinkan karena browser web mengirim beberapa jenis token autentikasi secara otomatis dengan setiap permintaan ke situs web. Bentuk eksploitasi ini juga dikenal sebagai serangan sekali klik atau pengambilalihan sesi karena serangan ini memanfaatkan sesi pengguna yang telah diautentikasi sebelumnya.
Contoh serangan CSRF:
Pengguna masuk ke
www.good-banking-site.example.commenggunakan autentikasi formulir. Server mengautentikasi pengguna dan mengeluarkan respons yang menyertakan autentikasi cookie. Situs ini rentan terhadap serangan karena mempercayai permintaan apa pun yang diterimanya dengan autentikasi cookieyang valid.Pengguna mengunjungi situs berbahaya,
www.bad-crook-site.example.com.Situs berbahaya,
www.bad-crook-site.example.com, berisi formulir HTML yang mirip dengan contoh berikut:<h1>Congratulations! You're a Winner!</h1> <form action="https://www.good-banking-site.example.com/api/account" method="post"> <input type="hidden" name="Transaction" value="withdraw" /> <input type="hidden" name="Amount" value="1000000" /> <input type="submit" value="Click to collect your prize!" /> </form>Perhatikan bahwa formulir
actionmengirimkan data ke situs rentan, bukan ke situs berbahaya. Ini adalah bagian "lintas situs" dari CSRF.Pengguna memilih tombol kirim. Browser membuat permintaan dan secara otomatis menyertakan autentikasi cookie untuk domain yang diminta,
www.good-banking-site.example.com.Permintaan berjalan di
www.good-banking-site.example.comserver dengan konteks autentikasi pengguna dan dapat melakukan tindakan apa pun yang diizinkan untuk dilakukan oleh pengguna terautentikasi.
Selain skenario di mana pengguna memilih tombol untuk mengirimkan formulir, situs berbahaya dapat:
- Jalankan skrip yang secara otomatis mengirimkan formulir.
- Kirim pengiriman formulir sebagai permintaan AJAX.
- Sembunyikan formulir menggunakan CSS.
Skenario alternatif ini tidak memerlukan tindakan atau input apa pun dari pengguna selain awalnya mengunjungi situs berbahaya.
Menggunakan HTTPS tidak mencegah serangan CSRF. Situs berbahaya dapat mengirim sebuah permintaan https://www.good-banking-site.example.com/ semudah mengirim permintaan tidak aman.
Beberapa serangan menargetkan titik akhir yang merespons permintaan GET, dalam hal ini tag gambar dapat digunakan untuk melakukan tindakan. Bentuk serangan ini umum terjadi di situs forum yang mengizinkan gambar tetapi memblokir JavaScript. Aplikasi yang mengubah status pada permintaan GET, di mana variabel atau sumber daya diubah, rentan terhadap serangan berbahaya. Permintaan GET yang mengubah status tidak aman. Praktik terbaik adalah tidak pernah mengubah status pada permintaan GET.
Serangan CSRF dimungkinkan terhadap aplikasi web yang menggunakan cookie untuk autentikasi karena:
- Browser menyimpan cookie yang dikeluarkan oleh aplikasi web.
- Cookie tersimpan mencakup cookie sesi untuk pengguna yang diautentikasi.
- Browser mengirim semua cookie yang terkait dengan domain ke aplikasi web setiap permintaan terlepas dari bagaimana permintaan ke aplikasi dihasilkan dalam browser.
Namun, serangan CSRF tidak terbatas pada mengeksploitasi cookie. Misalnya, autentikasi Dasar dan Digest juga rentan. Setelah pengguna masuk dengan autentikasi Dasar atau Digest, browser secara otomatis mengirimkan kredensial pengguna hingga sesi berakhir.
Dalam konteks ini, sesi mengacu pada sesi sisi klien tempat pengguna diautentikasi. Ini tidak terkait dengan sesi sisi server atau middleware sesi ASP.NET Core.
Pengguna dapat melindungi dari kerentanan CSRF dengan mengambil tindakan pencegahan:
- Keluar dari aplikasi web setelah selesai menggunakannya.
- Hapus cookie browser secara berkala.
Namun, kerentanan CSRF pada dasarnya merupakan masalah dengan aplikasi web, bukan pengguna akhir.
Dasar-dasar autentikasi
Autentikasi berbasis Cookie adalah bentuk autentikasi yang populer. Sistem autentikasi berbasis token semakin populer, terutama untuk Aplikasi Halaman Tunggal (SPAs).
Cookie-berbasis autentikasi
Saat pengguna mengautentikasi menggunakan nama pengguna dan kata sandi mereka, mereka mengeluarkan token, yang berisi tiket autentikasi yang dapat digunakan untuk autentikasi dan otorisasi. Token disimpan sebagai cookie yang dikirim dengan setiap permintaan yang dilakukan klien. Pembuatan dan validasi cookie ini dilakukan oleh cookie middleware autentikasi. Middleware mengubah prinsipal pengguna menjadi data terenkripsi cookie. Pada permintaan berikutnya, middleware memvalidasi cookie, membuat ulang entitas utama, dan menetapkan entitas utama ke properti HttpContext.User.
Autentikasi berbasis token
Saat pengguna diautentikasi, mereka diberikan token (bukan token antiforgery). Token berisi informasi pengguna dalam bentuk klaim atau token referensi yang menunjuk aplikasi ke status pengguna yang dipertahankan di aplikasi. Saat pengguna mencoba mengakses sumber daya yang memerlukan autentikasi, token dikirim ke aplikasi dengan header otorisasi tambahan dalam bentuk Bearer token. Pendekatan ini menjadikan aplikasi tidak bergantung pada status. Dalam setiap permintaan berikutnya, token diteruskan dalam permintaan validasi sisi server. Token ini tidak dienkripsi; dikodekan. Di server, token didekodekan untuk mengakses informasinya. Untuk mengirim token pada permintaan berikutnya, simpan token di penyimpanan lokal browser. Menempatkan token di penyimpanan lokal browser dan mengambilnya dan menggunakannya sebagai token pembawa memberikan perlindungan terhadap serangan CSRF. Namun, jika aplikasi rentan terhadap injeksi skrip melalui XSS atau file javascript eksternal yang disusupi, penyerang cyber dapat mengambil nilai apa pun dari penyimpanan lokal dan mengirimkannya ke diri mereka sendiri. ASP.NET Core mengodekan semua output sisi server dari variabel secara default, mengurangi risiko XSS. Jika Anda mengambil alih perilaku ini dengan menggunakan Html.Raw atau kode kustom dengan input yang tidak tepercaya, Maka Anda dapat meningkatkan risiko XSS.
Jangan khawatir tentang kerentanan CSRF jika token disimpan di penyimpanan lokal browser. CSRF menjadi perhatian ketika token disimpan dalam cookie. Untuk informasi selengkapnya, lihat isu GitHub tentang sampel kode SPA SPA code sample adds two cookies.
Beberapa aplikasi yang dihosting di satu domain
Lingkungan hosting bersama rentan terhadap pembajakan sesi, CSRF pada saat masuk, dan serangan lainnya.
Meskipun example1.contoso.net dan example2.contoso.net merupakan host yang berbeda, ada hubungan kepercayaan implisit antara host di *.contoso.net bawah domain. Hubungan kepercayaan implisit ini memungkinkan host yang berpotensi tidak tepercaya untuk memengaruhi cookie satu sama lain (kebijakan asal yang sama yang mengatur permintaan AJAX tidak selalu berlaku untuk cookie HTTP).
Serangan yang mengeksploitasi cookie tepercaya antara aplikasi yang dihosting di domain yang sama dapat dicegah dengan tidak berbagi domain. Saat setiap aplikasi dihosting di domainnya sendiri, tidak ada hubungan kepercayaan implisit cookie untuk dieksploitasi.
Anti-Pemalsuan dalam ASP.NET Core
Peringatan
ASP.NET Core mengimplementasikan antiforgery menggunakan ASP.NET Core Data Protection. Tumpukan perlindungan data harus dikonfigurasi untuk bekerja di farm server. Untuk informasi selengkapnya, lihat Mengonfigurasi perlindungan data.
Layanan anti-pemalsuan didaftarkan dalam kontainer injeksi dependensi saat salah satu API berikut dipanggil di Program.cs:
FormTagHelper menyuntikkan token anti-pemalsuan ke dalam elemen formulir HTML. Markup berikut dalam Razor file secara otomatis menghasilkan token antiforgery:
<form method="post">
<!-- ... -->
</form>
Demikian pula, IHtmlHelper.BeginForm menghasilkan token antiforgery secara default jika metode formulir bukan GET.
Pembuatan otomatis token antiforgery untuk elemen formulir HTML terjadi ketika <form> tag berisi method="post" atribut dan salah satu dari yang berikut ini benar:
- Atribut tindakan kosong (
action=""). - Atribut tindakan tidak disediakan (
<form method="post">).
Pembuatan token antiforgeri otomatis untuk elemen formulir HTML dapat dinonaktifkan:
Nonaktifkan token antiforgery secara eksplisit dengan
asp-antiforgeryatribut :<form method="post" asp-antiforgery="false"> <!-- ... --> </form>Elemen formulir ditolak dari Pembantu Tag dengan menggunakan simbol penolakan Pembantu Tag ! :
<!form method="post"> <!-- ... --> </!form>Hapus
FormTagHelperdari tampilan.FormTagHelperdapat dihapus dari tampilan dengan menambahkan direktif berikut ke Razor tampilan:@removeTagHelper Microsoft.AspNetCore.Mvc.TagHelpers.FormTagHelper, Microsoft.AspNetCore.Mvc.TagHelpers
Catatan
Razor Halaman secara otomatis dilindungi dari XSRF/CSRF. Untuk informasi selengkapnya, lihat XSRF/CSRF dan Razor Pages.
Pendekatan paling umum untuk bertahan dari serangan CSRF adalah menggunakan Synchronizer Token Pattern (STP). STP digunakan saat pengguna meminta halaman dengan data formulir:
- Server mengirim token yang terkait dengan identitas pengguna saat ini ke klien.
- Klien mengirim kembali token ke server untuk verifikasi.
- Jika server menerima token yang tidak cocok dengan identitas pengguna yang diautentikasi, permintaan akan ditolak.
Token unik dan tidak dapat diprediksi. Token juga dapat digunakan untuk memastikan urutan yang tepat dari serangkaian permintaan (misalnya, memastikan urutan permintaan: halaman 1 > halaman 2 > halaman 3). Semua formulir dalam templat ASP.NET Core MVC dan Razor Pages menghasilkan token antiforgery. Contoh tampilan berikut ini menghasilkan token anti-pemalsuan:
<form asp-action="Index" asp-controller="Home" method="post">
<!-- ... -->
</form>
@using (Html.BeginForm("Index", "Home"))
{
<!-- ... -->
}
Secara eksplisit tambahkan token antiforgery ke elemen <form> tanpa menggunakan Tag Helpers dengan HTML helper @Html.AntiForgeryToken.
<form asp-action="Index" asp-controller="Home" method="post">
@Html.AntiForgeryToken()
<!-- ... -->
</form>
Dalam setiap kasus sebelumnya, ASP.NET Core menambahkan bidang formulir tersembunyi yang mirip dengan contoh berikut:
<input name="__RequestVerificationToken" type="hidden" value="CfDJ8NrAkS ... s2-m9Yw">
ASP.NET Core mencakup tiga filter untuk menangani token antiforgery.
Penangkal Pemalsuan dengan AddControllers
AddControllers Panggilan tidak mengaktifkan token antiforgery. AddControllersWithViews harus dipanggil agar memiliki dukungan token antiforgery bawaan.
Beberapa tab browser dan Pola Token Sinkronisasi
Dengan Pola Token Penyinkronisasi, hanya halaman yang paling baru dimuat yang berisi token antiforgery yang valid. Menggunakan beberapa tab bisa bermasalah. Misalnya, jika pengguna membuka beberapa tab:
- Hanya tab yang terakhir dimuat yang berisi token antiforgery yang valid.
- Permintaan yang dibuat dari tab yang dimuat sebelumnya gagal dengan kesalahan:
Antiforgery token validation failed. The antiforgery cookie token and request token do not match
Pertimbangkan pola perlindungan CSRF alternatif jika ini menimbulkan masalah.
Mengonfigurasi fitur anti-pemalsuan dengan AntiforgeryOptions
Kustomisasi AntiforgeryOptions dalam file aplikasi Program :
builder.Services.AddAntiforgery(options =>
{
// Set Cookie properties using CookieBuilder properties†.
options.FormFieldName = "AntiforgeryFieldname";
options.HeaderName = "X-CSRF-TOKEN-HEADERNAME";
options.SuppressXFrameOptionsHeader = false;
});
Atur properti antiforgery cookie menggunakan properti kelas CookieBuilder, seperti yang ditunjukkan dalam tabel berikut.
| Opsi | Deskripsi |
|---|---|
| Cookie | Menentukan pengaturan yang digunakan untuk membuat cookie antiforgery. |
| FormFieldName | Nama kolom formulir tersembunyi yang digunakan oleh sistem antiforgery untuk memproses token antiforgery dalam tampilan. |
| HeaderName | Nama header yang digunakan oleh sistem anti-pemalsuan. Jika null, sistem hanya mempertimbangkan data formulir. |
| SuppressXFrameOptionsHeader | Menentukan apakah akan mengabaikan pembuatan header X-Frame-Options. Secara default, header dihasilkan dengan nilai "SAMEORIGIN". Bawaan ke false. |
Beberapa browser tidak mengizinkan titik akhir yang tidak aman untuk mengatur cookie dengan flag 'secure' atau menimpa cookie yang flag 'secure'-nya sudah diatur (untuk informasi selengkapnya, lihat Menyarankan untuk tidak memodifikasi cookie 'secure' dari asal yang tidak aman). Karena mencampur titik akhir yang aman dan tidak aman adalah skenario umum dalam aplikasi, ASP.NET Core melonggarkan pembatasan pada kebijakan aman pada beberapa cookie, seperti antiforgery cookie, dengan mengatur cookie dari SecurePolicy ke CookieSecurePolicy.None. Bahkan jika pengguna berbahaya mencuri antiforgery cookie, mereka juga harus mencuri token antiforgery yang biasanya dikirim melalui bidang formulir (lebih umum) atau header permintaan terpisah (kurang umum) ditambah autentikasi cookie.
Cookies terkait dengan autentikasi atau otorisasi menggunakan kebijakan yang lebih kuat daripada CookieSecurePolicy.None.
Secara opsional, Anda dapat mengamankan antiforgery cookie di lingkungan yang tidak menggunakan Development dengan menggunakan Secure Sockets Layer (SSL) melalui HTTPS saja, dengan pengaturan properti berikut AntiforgeryOptions.Cookie dalam file aplikasi Program :
if (!builder.Environment.IsDevelopment())
{
builder.Services.AddAntiforgery(o =>
{
o.Cookie.SecurePolicy = CookieSecurePolicy.Always;
});
}
Untuk informasi selengkapnya, lihat CookieAuthenticationOptions .
Hasilkan token anti-pemalsuan dengan IAntiforgery
IAntiforgery menyediakan API untuk mengonfigurasi fitur antiforgery.
IAntiforgery dapat diminta dalam Program.cs menggunakan WebApplication.Services. Contoh berikut ini menggunakan middleware dari halaman utama aplikasi untuk menghasilkan token antiforgery dan mengirimkannya dalam respons sebagai cookie:
app.UseRouting();
app.UseAuthorization();
var antiforgery = app.Services.GetRequiredService<IAntiforgery>();
app.Use((context, next) =>
{
var requestPath = context.Request.Path.Value;
if (string.Equals(requestPath, "/", StringComparison.OrdinalIgnoreCase)
|| string.Equals(requestPath, "/index.html", StringComparison.OrdinalIgnoreCase))
{
var tokenSet = antiforgery.GetAndStoreTokens(context);
context.Response.Cookies.Append("XSRF-TOKEN", tokenSet.RequestToken!,
new CookieOptions { HttpOnly = false });
}
return next(context);
});
Contoh sebelumnya menetapkan sebuah cookie yang diberi nama XSRF-TOKEN. Klien dapat membaca ini cookie dan memberikan nilainya sebagai header yang dilampirkan ke permintaan AJAX. Misalnya, Angular menyertakan perlindungan XSRF bawaan yang secara default membaca sebuah elemen bernama cookieXSRF-TOKEN.
Memerlukan validasi pencegahan pemalsuan
Filter aksi ValidateAntiForgeryToken dapat diterapkan ke aksi individu, kontroler, atau secara global. Permintaan yang dibuat untuk tindakan yang menerapkan filter ini diblokir kecuali permintaan menyertakan token antiforgery yang valid:
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Index()
{
// ...
return RedirectToAction();
}
Atribut ValidateAntiForgeryToken memerlukan token untuk permintaan ke metode tindakan yang ditandainya, termasuk permintaan HTTP GET. Jika atribut ValidateAntiForgeryToken diterapkan di seluruh pengontrol aplikasi, atribut tersebut dapat ditimpa dengan atribut IgnoreAntiforgeryToken.
Memvalidasi secara otomatis token antiforgery hanya untuk metode HTTP yang dianggap tidak aman.
Alih-alih menerapkan atribut ValidateAntiForgeryToken secara luas dan kemudian menimpanya dengan atribut IgnoreAntiforgeryToken, atribut AutoValidateAntiforgeryToken dapat digunakan. Atribut ini berfungsi secara identik dengan ValidateAntiForgeryToken atribut , kecuali bahwa atribut ini tidak memerlukan token untuk permintaan yang dibuat menggunakan metode HTTP berikut:
- DAPATKAN
- Kepala
- OPSI
- TRACE
Sebaiknya gunakan AutoValidateAntiforgeryToken secara luas untuk skenario non-API. Atribut ini memastikan tindakan POST dilindungi secara default. Alternatifnya adalah mengabaikan token antiforgery secara default, kecuali ValidateAntiForgeryToken diterapkan ke metode tindakan individual. Dalam skenario ini, lebih mungkin metode tindakan POST dibiarkan tidak terlindungi secara tidak sengaja, membuat aplikasi rentan terhadap serangan CSRF. Semua POS harus mengirim token antiforgery.
API tidak memiliki mekanisme otomatis untuk mengirimkan bagian dari token yang bukan cookie. Implementasi mungkin tergantung pada implementasi kode klien. Beberapa contoh ditunjukkan di bawah ini:
Contoh pada tingkat kelas:
[AutoValidateAntiforgeryToken]
public class HomeController : Controller
Contoh global:
builder.Services.AddControllersWithViews(options =>
{
options.Filters.Add(new AutoValidateAntiforgeryTokenAttribute());
});
Mengambil alih atribut antiforgery global atau pengontrol
Filter IgnoreAntiforgeryToken digunakan untuk menghilangkan kebutuhan token antiforgery untuk tindakan tertentu (atau pengontrol). Ketika diterapkan, filter ini akan mengesampingkan filter ValidateAntiForgeryToken dan AutoValidateAntiforgeryToken yang ditentukan pada tingkat yang lebih tinggi (secara global atau pada pengontrol).
[IgnoreAntiforgeryToken]
public IActionResult IndexOverride()
{
// ...
return RedirectToAction();
}
Penyegaran token setelah autentikasi
Token harus di-refresh setelah pengguna diautentikasi dengan mengalihkan pengguna ke halaman tampilan atau Razor Halaman.
JavaScript, AJAX, dan SPAs
Dalam aplikasi tradisional berbasis HTML, token antiforgery dikirimkan ke server menggunakan kolom formulir tersembunyi. Di aplikasi dan SPAs berbasis JavaScript modern, banyak permintaan dibuat secara terprogram. Permintaan AJAX ini dapat menggunakan teknik lain (seperti header permintaan atau cookie) untuk mengirim token.
Jika cookie digunakan untuk menyimpan token autentikasi dan untuk mengautentikasi permintaan API di server, CSRF adalah masalah potensial. Jika penyimpanan lokal digunakan untuk menyimpan token, kerentanan CSRF mungkin dimitigasi karena nilai dari penyimpanan lokal tidak dikirim secara otomatis ke server dengan setiap permintaan. Menggunakan penyimpanan lokal untuk menyimpan token antiforgery pada klien dan mengirim token sebagai header permintaan adalah pendekatan yang direkomendasikan.
JavaScript
Dengan menggunakan JavaScript pada tampilan, token dapat dibuat menggunakan layanan dari dalam tampilan tersebut. IAntiforgery Masukkan layanan ke dalam tampilan dan panggil GetAndStoreTokens:
@inject Microsoft.AspNetCore.Antiforgery.IAntiforgery Antiforgery
@{
ViewData["Title"] = "JavaScript";
var requestToken = Antiforgery.GetAndStoreTokens(Context).RequestToken;
}
<input id="RequestVerificationToken" type="hidden" value="@requestToken" />
<button id="button" class="btn btn-primary">Submit with Token</button>
<div id="result" class="mt-2"></div>
@section Scripts {
<script>
document.addEventListener("DOMContentLoaded", () => {
const resultElement = document.getElementById("result");
document.getElementById("button").addEventListener("click", async () => {
const response = await fetch("@Url.Action("FetchEndpoint")", {
method: "POST",
headers: {
RequestVerificationToken:
document.getElementById("RequestVerificationToken").value
}
});
if (response.ok) {
resultElement.innerText = await response.text();
} else {
resultElement.innerText = `Request Failed: ${response.status}`
}
});
});
</script>
}
Contoh sebelumnya menggunakan JavaScript untuk membaca nilai bidang tersembunyi untuk header AJAX POST.
Pendekatan ini menghilangkan kebutuhan untuk berurusan langsung dengan pengaturan cookie dari server atau membacanya dari klien. Namun, jika menyuntikkan layanan IAntiforgery tidak memungkinkan, gunakan JavaScript untuk mengakses token dalam cookie.
- Akses token dalam permintaan tambahan ke server, biasanya
same-origin. - Gunakan konten dari cookie untuk membuat header dengan nilai token.
Dengan asumsi skrip mengirimkan token di header permintaan yang disebutkan X-XSRF-TOKEN, konfigurasikan layanan antiforgery untuk mencari header X-XSRF-TOKEN.
builder.Services.AddAntiforgery(options => options.HeaderName = "X-XSRF-TOKEN");
Contoh berikut menambahkan titik akhir terproteksi yang menulis token permintaan ke JavaScript yang dapat cookiedibaca :
app.UseAuthorization();
app.MapGet("antiforgery/token", (IAntiforgery forgeryService, HttpContext context) =>
{
var tokens = forgeryService.GetAndStoreTokens(context);
context.Response.Cookies.Append("XSRF-TOKEN", tokens.RequestToken!,
new CookieOptions { HttpOnly = false });
return Results.Ok();
}).RequireAuthorization();
Contoh berikut menggunakan JavaScript untuk membuat permintaan AJAX untuk mendapatkan token dan membuat permintaan lain dengan header yang sesuai:
var response = await fetch("/antiforgery/token", {
method: "GET",
headers: { "Authorization": authorizationToken }
});
if (response.ok) {
// https://developer.mozilla.org/docs/web/api/document/cookie
const xsrfToken = document.cookie
.split("; ")
.find(row => row.startsWith("XSRF-TOKEN="))
.split("=")[1];
response = await fetch("/JavaScript/FetchEndpoint", {
method: "POST",
headers: { "X-XSRF-TOKEN": xsrfToken, "Authorization": authorizationToken }
});
if (response.ok) {
resultElement.innerText = await response.text();
} else {
resultElement.innerText = `Request Failed: ${response.status}`
}
} else {
resultElement.innerText = `Request Failed: ${response.status}`
}
Catatan
Ketika token antiforgery disediakan di header permintaan dan dalam payload formulir, hanya token di header yang divalidasi.
Pencegahan Pemalsuan dengan API Minimal
Minimal APIstidak mendukung penggunaan filter yang disertakan (ValidateAntiForgeryToken, , AutoValidateAntiforgeryTokenIgnoreAntiforgeryToken), namun, IAntiforgery menyediakan API yang diperlukan untuk memvalidasi permintaan.
Contoh berikut membuat filter yang memverifikasi token anti-pemalsuan.
internal static class AntiForgeryExtensions
{
public static TBuilder ValidateAntiforgery<TBuilder>(this TBuilder builder) where TBuilder : IEndpointConventionBuilder
{
return builder.AddEndpointFilter(routeHandlerFilter: async (context, next) =>
{
try
{
var antiForgeryService = context.HttpContext.RequestServices.GetRequiredService<IAntiforgery>();
await antiForgeryService.ValidateRequestAsync(context.HttpContext);
}
catch (AntiforgeryValidationException)
{
return Results.BadRequest("Antiforgery token validation failed.");
}
return await next(context);
});
}
}
Filter kemudian dapat diterapkan ke titik akhir:
app.MapPost("api/upload", (IFormFile name) => Results.Accepted())
.RequireAuthorization()
.ValidateAntiforgery();
Autentikasi Windows dan kuki anti-pemalsuan
Saat menggunakan Autentikasi Windows, titik akhir aplikasi harus dilindungi dari serangan CSRF dengan cara yang sama seperti yang dilakukan untuk cookie. Browser secara implisit mengirim konteks autentikasi ke server dan titik akhir perlu dilindungi dari serangan CSRF.
Perluas fitur anti-pemalsuan
Jenis ini IAntiforgeryAdditionalDataProvider memungkinkan pengembang untuk memperpanjang fungsi sistem anti-CSRF dengan memutar alihkan data tambahan di setiap token. Metode GetAdditionalData ini dipanggil setiap kali token bidang dihasilkan, dan nilai pengembalian disematkan dalam token yang dihasilkan. Pelaksana dapat mengembalikan tanda waktu, nonce, atau nilai lain lalu memanggil ValidateAdditionalData untuk memvalidasi data ini saat token divalidasi. Nama pengguna klien sudah disematkan dalam token yang dihasilkan, sehingga tidak perlu menyertakan informasi ini. Jika token menyertakan data tambahan tetapi tidak IAntiForgeryAdditionalDataProvider dikonfigurasi, data tambahan tidak divalidasi.
Sumber Daya Tambahan:
Pemalsuan permintaan lintas situs (juga dikenal sebagai XSRF atau CSRF) adalah serangan terhadap aplikasi yang dihosting web di mana aplikasi web berbahaya dapat memengaruhi interaksi antara browser klien dan aplikasi web yang mempercayai browser tersebut. Serangan ini dimungkinkan karena browser web mengirim beberapa jenis token autentikasi secara otomatis dengan setiap permintaan ke situs web. Bentuk eksploitasi ini juga dikenal sebagai serangan sekali klik atau pengambilalihan sesi karena serangan ini memanfaatkan sesi pengguna yang telah diautentikasi sebelumnya.
Contoh serangan CSRF:
Pengguna masuk ke
www.good-banking-site.example.commenggunakan autentikasi formulir. Server mengautentikasi pengguna dan mengeluarkan respons yang menyertakan autentikasi cookie. Situs ini rentan terhadap serangan karena mempercayai permintaan apa pun yang diterimanya dengan autentikasi cookieyang valid.Pengguna mengunjungi situs berbahaya,
www.bad-crook-site.example.com.Situs berbahaya,
www.bad-crook-site.example.com, berisi formulir HTML yang mirip dengan contoh berikut:<h1>Congratulations! You're a Winner!</h1> <form action="https://www.good-banking-site.example.com/api/account" method="post"> <input type="hidden" name="Transaction" value="withdraw" /> <input type="hidden" name="Amount" value="1000000" /> <input type="submit" value="Click to collect your prize!" /> </form>Perhatikan bahwa formulir
actionmengirimkan data ke situs rentan, bukan ke situs berbahaya. Ini adalah bagian "lintas situs" dari CSRF.Pengguna memilih tombol kirim. Browser membuat permintaan dan secara otomatis menyertakan autentikasi cookie untuk domain yang diminta,
www.good-banking-site.example.com.Permintaan berjalan di
www.good-banking-site.example.comserver dengan konteks autentikasi pengguna dan dapat melakukan tindakan apa pun yang diizinkan untuk dilakukan oleh pengguna terautentikasi.
Selain skenario di mana pengguna memilih tombol untuk mengirimkan formulir, situs berbahaya dapat:
- Jalankan skrip yang secara otomatis mengirimkan formulir.
- Kirim pengiriman formulir sebagai permintaan AJAX.
- Sembunyikan formulir menggunakan CSS.
Skenario alternatif ini tidak memerlukan tindakan atau input apa pun dari pengguna selain awalnya mengunjungi situs berbahaya.
Menggunakan HTTPS tidak mencegah serangan CSRF. Situs berbahaya dapat mengirim sebuah permintaan https://www.good-banking-site.example.com/ semudah mengirim permintaan tidak aman.
Beberapa serangan menargetkan titik akhir yang merespons permintaan GET, dalam hal ini tag gambar dapat digunakan untuk melakukan tindakan. Bentuk serangan ini umum terjadi di situs forum yang mengizinkan gambar tetapi memblokir JavaScript. Aplikasi yang mengubah status pada permintaan GET, di mana variabel atau sumber daya diubah, rentan terhadap serangan berbahaya. Permintaan GET yang mengubah status tidak aman. Praktik terbaik adalah tidak pernah mengubah status pada permintaan GET.
Serangan CSRF dimungkinkan terhadap aplikasi web yang menggunakan cookie untuk autentikasi karena:
- Browser menyimpan cookie yang dikeluarkan oleh aplikasi web.
- Cookie tersimpan mencakup cookie sesi untuk pengguna yang diautentikasi.
- Browser mengirim semua cookie yang terkait dengan domain ke aplikasi web setiap permintaan terlepas dari bagaimana permintaan ke aplikasi dihasilkan dalam browser.
Namun, serangan CSRF tidak terbatas pada mengeksploitasi cookie. Misalnya, autentikasi Dasar dan Digest juga rentan. Setelah pengguna masuk dengan autentikasi Dasar atau Digest, browser secara otomatis mengirimkan kredensial pengguna hingga sesi berakhir.
Dalam konteks ini, sesi mengacu pada sesi sisi klien tempat pengguna diautentikasi. Ini tidak terkait dengan sesi sisi server atau middleware sesi ASP.NET Core.
Pengguna dapat melindungi dari kerentanan CSRF dengan mengambil tindakan pencegahan:
- Keluar dari aplikasi web setelah selesai menggunakannya.
- Hapus cookie browser secara berkala.
Namun, kerentanan CSRF pada dasarnya merupakan masalah dengan aplikasi web, bukan pengguna akhir.
Dasar-dasar autentikasi
Autentikasi berbasis Cookie adalah bentuk autentikasi yang populer. Sistem autentikasi berbasis token semakin populer, terutama untuk Aplikasi Halaman Tunggal (SPAs).
Cookie-berbasis autentikasi
Saat pengguna mengautentikasi menggunakan nama pengguna dan kata sandi mereka, mereka mengeluarkan token, yang berisi tiket autentikasi yang dapat digunakan untuk autentikasi dan otorisasi. Token disimpan sebagai cookie yang dikirim dengan setiap permintaan yang dilakukan klien. Pembuatan dan validasi cookie ini dilakukan oleh cookie middleware autentikasi. Middleware mengubah prinsipal pengguna menjadi data terenkripsi cookie. Pada permintaan berikutnya, middleware memvalidasi cookie, membuat ulang entitas utama, dan menetapkan entitas utama ke properti HttpContext.User.
Autentikasi berbasis token
Saat pengguna diautentikasi, mereka diberikan token (bukan token antiforgery). Token berisi informasi pengguna dalam bentuk klaim atau token referensi yang menunjuk aplikasi ke status pengguna yang dipertahankan di aplikasi. Saat pengguna mencoba mengakses sumber daya yang memerlukan autentikasi, token dikirim ke aplikasi dengan header otorisasi tambahan dalam bentuk Bearer token. Pendekatan ini menjadikan aplikasi tidak bergantung pada status. Dalam setiap permintaan berikutnya, token diteruskan dalam permintaan validasi sisi server. Token ini tidak dienkripsi; dikodekan. Di server, token didekodekan untuk mengakses informasinya. Untuk mengirim token pada permintaan berikutnya, simpan token di penyimpanan lokal browser. Jangan khawatir tentang kerentanan CSRF jika token disimpan di penyimpanan lokal browser. CSRF menjadi perhatian ketika token disimpan dalam cookie. Untuk informasi selengkapnya, lihat isu GitHub tentang sampel kode SPA SPA code sample adds two cookies.
Beberapa aplikasi yang dihosting di satu domain
Lingkungan hosting bersama rentan terhadap pembajakan sesi, CSRF pada saat masuk, dan serangan lainnya.
Meskipun example1.contoso.net dan example2.contoso.net merupakan host yang berbeda, ada hubungan kepercayaan implisit antara host di *.contoso.net bawah domain. Hubungan kepercayaan implisit ini memungkinkan host yang berpotensi tidak tepercaya untuk memengaruhi cookie satu sama lain (kebijakan asal yang sama yang mengatur permintaan AJAX tidak selalu berlaku untuk cookie HTTP).
Serangan yang mengeksploitasi cookie tepercaya antara aplikasi yang dihosting di domain yang sama dapat dicegah dengan tidak berbagi domain. Saat setiap aplikasi dihosting di domainnya sendiri, tidak ada hubungan kepercayaan implisit cookie untuk dieksploitasi.
Anti-Pemalsuan dalam ASP.NET Core
Peringatan
ASP.NET Core mengimplementasikan antiforgery menggunakan ASP.NET Core Data Protection. Tumpukan perlindungan data harus dikonfigurasi untuk bekerja di farm server. Untuk informasi selengkapnya, lihat Mengonfigurasi perlindungan data.
Middleware antiforgery ditambahkan ke kontainer Injeksi Dependensi ketika salah satu API berikut dipanggil di Program.cs:
FormTagHelper menyuntikkan token anti-pemalsuan ke dalam elemen formulir HTML. Markup berikut dalam Razor file secara otomatis menghasilkan token antiforgery:
<form method="post">
<!-- ... -->
</form>
Demikian pula, IHtmlHelper.BeginForm menghasilkan token antiforgery secara default jika metode formulir bukan GET.
Pembuatan otomatis token antiforgery untuk elemen formulir HTML terjadi ketika <form> tag berisi method="post" atribut dan salah satu dari yang berikut ini benar:
- Atribut tindakan kosong (
action=""). - Atribut tindakan tidak disediakan (
<form method="post">).
Pembuatan token antiforgeri otomatis untuk elemen formulir HTML dapat dinonaktifkan:
Nonaktifkan token antiforgery secara eksplisit dengan
asp-antiforgeryatribut :<form method="post" asp-antiforgery="false"> <!-- ... --> </form>Elemen formulir ditolak dari Pembantu Tag dengan menggunakan simbol penolakan Pembantu Tag ! :
<!form method="post"> <!-- ... --> </!form>Hapus
FormTagHelperdari tampilan.FormTagHelperdapat dihapus dari tampilan dengan menambahkan direktif berikut ke Razor tampilan:@removeTagHelper Microsoft.AspNetCore.Mvc.TagHelpers.FormTagHelper, Microsoft.AspNetCore.Mvc.TagHelpers
Catatan
Razor Halaman secara otomatis dilindungi dari XSRF/CSRF. Untuk informasi selengkapnya, lihat XSRF/CSRF dan Razor Pages.
Pendekatan paling umum untuk bertahan dari serangan CSRF adalah menggunakan Synchronizer Token Pattern (STP). STP digunakan saat pengguna meminta halaman dengan data formulir:
- Server mengirim token yang terkait dengan identitas pengguna saat ini ke klien.
- Klien mengirim kembali token ke server untuk verifikasi.
- Jika server menerima token yang tidak cocok dengan identitas pengguna yang diautentikasi, permintaan akan ditolak.
Token unik dan tidak dapat diprediksi. Token juga dapat digunakan untuk memastikan urutan yang tepat dari serangkaian permintaan (misalnya, memastikan urutan permintaan: halaman 1 > halaman 2 > halaman 3). Semua formulir dalam templat ASP.NET Core MVC dan Razor Pages menghasilkan token antiforgery. Contoh tampilan berikut ini menghasilkan token anti-pemalsuan:
<form asp-action="Index" asp-controller="Home" method="post">
<!-- ... -->
</form>
@using (Html.BeginForm("Index", "Home"))
{
<!-- ... -->
}
Secara eksplisit tambahkan token antiforgery ke elemen <form> tanpa menggunakan Tag Helpers dengan HTML helper @Html.AntiForgeryToken.
<form asp-action="Index" asp-controller="Home" method="post">
@Html.AntiForgeryToken()
<!-- ... -->
</form>
Dalam setiap kasus sebelumnya, ASP.NET Core menambahkan bidang formulir tersembunyi yang mirip dengan contoh berikut:
<input name="__RequestVerificationToken" type="hidden" value="CfDJ8NrAkS ... s2-m9Yw">
ASP.NET Core mencakup tiga filter untuk menangani token antiforgery.
Penangkal Pemalsuan dengan AddControllers
AddControllers Panggilan tidak mengaktifkan token antiforgery. AddControllersWithViews harus dipanggil agar memiliki dukungan token antiforgery bawaan.
Beberapa tab browser dan Pola Token Sinkronisasi
Dengan Pola Token Penyinkronisasi, hanya halaman yang paling baru dimuat yang berisi token antiforgery yang valid. Menggunakan beberapa tab bisa bermasalah. Misalnya, jika pengguna membuka beberapa tab:
- Hanya tab yang terakhir dimuat yang berisi token antiforgery yang valid.
- Permintaan yang dibuat dari tab yang dimuat sebelumnya gagal dengan kesalahan:
Antiforgery token validation failed. The antiforgery cookie token and request token do not match
Pertimbangkan pola perlindungan CSRF alternatif jika ini menimbulkan masalah.
Mengonfigurasi fitur anti-pemalsuan dengan AntiforgeryOptions
Kustomisasi AntiforgeryOptions dalam file aplikasi Program :
builder.Services.AddAntiforgery(options =>
{
// Set Cookie properties using CookieBuilder properties†.
options.FormFieldName = "AntiforgeryFieldname";
options.HeaderName = "X-CSRF-TOKEN-HEADERNAME";
options.SuppressXFrameOptionsHeader = false;
});
Atur properti antiforgery cookie menggunakan properti kelas CookieBuilder, seperti yang ditunjukkan dalam tabel berikut.
| Opsi | Deskripsi |
|---|---|
| Cookie | Menentukan pengaturan yang digunakan untuk membuat cookie antiforgery. |
| FormFieldName | Nama kolom formulir tersembunyi yang digunakan oleh sistem antiforgery untuk memproses token antiforgery dalam tampilan. |
| HeaderName | Nama header yang digunakan oleh sistem anti-pemalsuan. Jika null, sistem hanya mempertimbangkan data formulir. |
| SuppressXFrameOptionsHeader | Menentukan apakah akan mengabaikan pembuatan header X-Frame-Options. Secara default, header dihasilkan dengan nilai "SAMEORIGIN". Bawaan ke false. |
Beberapa browser tidak mengizinkan titik akhir yang tidak aman untuk mengatur cookie dengan flag 'secure' atau menimpa cookie yang flag 'secure'-nya sudah diatur (untuk informasi selengkapnya, lihat Menyarankan untuk tidak memodifikasi cookie 'secure' dari asal yang tidak aman). Karena mencampur titik akhir yang aman dan tidak aman adalah skenario umum dalam aplikasi, ASP.NET Core melonggarkan pembatasan pada kebijakan aman pada beberapa cookie, seperti antiforgery cookie, dengan mengatur cookie dari SecurePolicy ke CookieSecurePolicy.None. Bahkan jika pengguna berbahaya mencuri antiforgery cookie, mereka juga harus mencuri token antiforgery yang biasanya dikirim melalui bidang formulir (lebih umum) atau header permintaan terpisah (kurang umum) ditambah autentikasi cookie.
Cookies terkait dengan autentikasi atau otorisasi menggunakan kebijakan yang lebih kuat daripada CookieSecurePolicy.None.
Secara opsional, Anda dapat mengamankan antiforgery cookie di lingkungan yang tidak menggunakan Development dengan menggunakan Secure Sockets Layer (SSL) melalui HTTPS saja, dengan pengaturan properti berikut AntiforgeryOptions.Cookie dalam file aplikasi Program :
if (!builder.Environment.IsDevelopment())
{
builder.Services.AddAntiforgery(o =>
{
o.Cookie.SecurePolicy = CookieSecurePolicy.Always;
});
}
Untuk informasi selengkapnya, lihat CookieAuthenticationOptions .
Hasilkan token anti-pemalsuan dengan IAntiforgery
IAntiforgery menyediakan API untuk mengonfigurasi fitur antiforgery.
IAntiforgery dapat diminta dalam Program.cs menggunakan WebApplication.Services. Contoh berikut ini menggunakan middleware dari halaman utama aplikasi untuk menghasilkan token antiforgery dan mengirimkannya dalam respons sebagai cookie:
app.UseRouting();
app.UseAuthorization();
var antiforgery = app.Services.GetRequiredService<IAntiforgery>();
app.Use((context, next) =>
{
var requestPath = context.Request.Path.Value;
if (string.Equals(requestPath, "/", StringComparison.OrdinalIgnoreCase)
|| string.Equals(requestPath, "/index.html", StringComparison.OrdinalIgnoreCase))
{
var tokenSet = antiforgery.GetAndStoreTokens(context);
context.Response.Cookies.Append("XSRF-TOKEN", tokenSet.RequestToken!,
new CookieOptions { HttpOnly = false });
}
return next(context);
});
Contoh sebelumnya menetapkan sebuah cookie yang diberi nama XSRF-TOKEN. Klien dapat membaca ini cookie dan memberikan nilainya sebagai header yang dilampirkan ke permintaan AJAX. Misalnya, Angular menyertakan perlindungan XSRF bawaan yang secara default membaca sebuah elemen bernama cookieXSRF-TOKEN.
Memerlukan validasi pencegahan pemalsuan
Filter aksi ValidateAntiForgeryToken dapat diterapkan ke aksi individu, kontroler, atau secara global. Permintaan yang dibuat untuk tindakan yang menerapkan filter ini diblokir kecuali permintaan menyertakan token antiforgery yang valid:
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Index()
{
// ...
return RedirectToAction();
}
Atribut ValidateAntiForgeryToken memerlukan token untuk permintaan ke metode tindakan yang ditandainya, termasuk permintaan HTTP GET. Jika atribut ValidateAntiForgeryToken diterapkan di seluruh pengontrol aplikasi, atribut tersebut dapat ditimpa dengan atribut IgnoreAntiforgeryToken.
Memvalidasi secara otomatis token antiforgery hanya untuk metode HTTP yang dianggap tidak aman.
Alih-alih menerapkan atribut ValidateAntiForgeryToken secara luas dan kemudian menimpanya dengan atribut IgnoreAntiforgeryToken, atribut AutoValidateAntiforgeryToken dapat digunakan. Atribut ini berfungsi secara identik dengan ValidateAntiForgeryToken atribut , kecuali bahwa atribut ini tidak memerlukan token untuk permintaan yang dibuat menggunakan metode HTTP berikut:
- DAPATKAN
- Kepala
- OPSI
- TRACE
Sebaiknya gunakan AutoValidateAntiforgeryToken secara luas untuk skenario non-API. Atribut ini memastikan tindakan POST dilindungi secara default. Alternatifnya adalah mengabaikan token antiforgery secara default, kecuali ValidateAntiForgeryToken diterapkan ke metode tindakan individual. Dalam skenario ini, lebih mungkin metode tindakan POST dibiarkan tidak terlindungi secara tidak sengaja, membuat aplikasi rentan terhadap serangan CSRF. Semua POS harus mengirim token antiforgery.
API tidak memiliki mekanisme otomatis untuk mengirimkan bagian dari token yang bukan cookie. Implementasi mungkin tergantung pada implementasi kode klien. Beberapa contoh ditunjukkan di bawah ini:
Contoh pada tingkat kelas:
[AutoValidateAntiforgeryToken]
public class HomeController : Controller
Contoh global:
builder.Services.AddControllersWithViews(options =>
{
options.Filters.Add(new AutoValidateAntiforgeryTokenAttribute());
});
Mengambil alih atribut antiforgery global atau pengontrol
Filter IgnoreAntiforgeryToken digunakan untuk menghilangkan kebutuhan token antiforgery untuk tindakan tertentu (atau pengontrol). Ketika diterapkan, filter ini akan mengesampingkan filter ValidateAntiForgeryToken dan AutoValidateAntiforgeryToken yang ditentukan pada tingkat yang lebih tinggi (secara global atau pada pengontrol).
[IgnoreAntiforgeryToken]
public IActionResult IndexOverride()
{
// ...
return RedirectToAction();
}
Penyegaran token setelah autentikasi
Token harus di-refresh setelah pengguna diautentikasi dengan mengalihkan pengguna ke halaman tampilan atau Razor Halaman.
JavaScript, AJAX, dan SPAs
Dalam aplikasi tradisional berbasis HTML, token antiforgery dikirimkan ke server menggunakan kolom formulir tersembunyi. Di aplikasi dan SPAs berbasis JavaScript modern, banyak permintaan dibuat secara terprogram. Permintaan AJAX ini dapat menggunakan teknik lain (seperti header permintaan atau cookie) untuk mengirim token.
Jika cookie digunakan untuk menyimpan token autentikasi dan untuk mengautentikasi permintaan API di server, CSRF adalah masalah potensial. Jika penyimpanan lokal digunakan untuk menyimpan token, kerentanan CSRF mungkin dimitigasi karena nilai dari penyimpanan lokal tidak dikirim secara otomatis ke server dengan setiap permintaan. Menggunakan penyimpanan lokal untuk menyimpan token antiforgery pada klien dan mengirim token sebagai header permintaan adalah pendekatan yang direkomendasikan.
JavaScript
Dengan menggunakan JavaScript pada tampilan, token dapat dibuat menggunakan layanan dari dalam tampilan tersebut. IAntiforgery Masukkan layanan ke dalam tampilan dan panggil GetAndStoreTokens:
@inject Microsoft.AspNetCore.Antiforgery.IAntiforgery Antiforgery
@{
ViewData["Title"] = "JavaScript";
var requestToken = Antiforgery.GetAndStoreTokens(Context).RequestToken;
}
<input id="RequestVerificationToken" type="hidden" value="@requestToken" />
<button id="button" class="btn btn-primary">Submit with Token</button>
<div id="result" class="mt-2"></div>
@section Scripts {
<script>
document.addEventListener("DOMContentLoaded", () => {
const resultElement = document.getElementById("result");
document.getElementById("button").addEventListener("click", async () => {
const response = await fetch("@Url.Action("FetchEndpoint")", {
method: "POST",
headers: {
RequestVerificationToken:
document.getElementById("RequestVerificationToken").value
}
});
if (response.ok) {
resultElement.innerText = await response.text();
} else {
resultElement.innerText = `Request Failed: ${response.status}`
}
});
});
</script>
}
Contoh sebelumnya menggunakan JavaScript untuk membaca nilai bidang tersembunyi untuk header AJAX POST.
Pendekatan ini menghilangkan kebutuhan untuk berurusan langsung dengan pengaturan cookie dari server atau membacanya dari klien. Namun, ketika penyuntikan layanan IAntiforgery tidak memungkinkan, JavaScript juga dapat mengakses token dalam cookie yang diperoleh dari permintaan tambahan ke server (biasanya same-origin), dan menggunakan konten dari cookie untuk membuat header dengan nilai token.
Dengan asumsi skrip mengirimkan token di header permintaan yang disebutkan X-XSRF-TOKEN, konfigurasikan layanan antiforgery untuk mencari header X-XSRF-TOKEN.
builder.Services.AddAntiforgery(options => options.HeaderName = "X-XSRF-TOKEN");
Contoh berikut menambahkan titik akhir terproteksi yang akan menulis token permintaan ke JavaScript yang dapat cookiedibaca :
app.UseAuthorization();
app.MapGet("antiforgery/token", (IAntiforgery forgeryService, HttpContext context) =>
{
var tokens = forgeryService.GetAndStoreTokens(context);
context.Response.Cookies.Append("XSRF-TOKEN", tokens.RequestToken!,
new CookieOptions { HttpOnly = false });
return Results.Ok();
}).RequireAuthorization();
Contoh berikut menggunakan JavaScript untuk membuat permintaan AJAX untuk mendapatkan token dan membuat permintaan lain dengan header yang sesuai:
var response = await fetch("/antiforgery/token", {
method: "GET",
headers: { "Authorization": authorizationToken }
});
if (response.ok) {
// https://developer.mozilla.org/docs/web/api/document/cookie
const xsrfToken = document.cookie
.split("; ")
.find(row => row.startsWith("XSRF-TOKEN="))
.split("=")[1];
response = await fetch("/JavaScript/FetchEndpoint", {
method: "POST",
headers: { "X-XSRF-TOKEN": xsrfToken, "Authorization": authorizationToken }
});
if (response.ok) {
resultElement.innerText = await response.text();
} else {
resultElement.innerText = `Request Failed: ${response.status}`
}
} else {
resultElement.innerText = `Request Failed: ${response.status}`
}
Autentikasi Windows dan kuki anti-pemalsuan
Saat menggunakan Autentikasi Windows, titik akhir aplikasi harus dilindungi dari serangan CSRF dengan cara yang sama seperti yang dilakukan untuk cookie. Browser secara implisit mengirim konteks autentikasi ke server sehingga titik akhir perlu dilindungi dari serangan CSRF.
Perluas fitur anti-pemalsuan
Jenis ini IAntiforgeryAdditionalDataProvider memungkinkan pengembang untuk memperpanjang fungsi sistem anti-CSRF dengan memutar alihkan data tambahan di setiap token. Metode GetAdditionalData ini dipanggil setiap kali token bidang dihasilkan, dan nilai pengembalian disematkan dalam token yang dihasilkan. Pelaksana dapat mengembalikan tanda waktu, nonce, atau nilai lain lalu memanggil ValidateAdditionalData untuk memvalidasi data ini saat token divalidasi. Nama pengguna klien sudah disematkan dalam token yang dihasilkan, sehingga tidak perlu menyertakan informasi ini. Jika token menyertakan data tambahan tetapi tidak IAntiForgeryAdditionalDataProvider dikonfigurasi, data tambahan tidak divalidasi.
Sumber Daya Tambahan:
Pemalsuan permintaan lintas situs (juga dikenal sebagai XSRF atau CSRF) adalah serangan terhadap aplikasi yang dihosting web di mana aplikasi web berbahaya dapat memengaruhi interaksi antara browser klien dan aplikasi web yang mempercayai browser tersebut. Serangan ini dimungkinkan karena browser web mengirim beberapa jenis token autentikasi secara otomatis dengan setiap permintaan ke situs web. Bentuk eksploitasi ini juga dikenal sebagai serangan sekali klik atau pengambilalihan sesi karena serangan ini memanfaatkan sesi pengguna yang telah diautentikasi sebelumnya.
Contoh serangan CSRF:
Pengguna masuk ke
www.good-banking-site.example.commenggunakan autentikasi formulir. Server mengautentikasi pengguna dan mengeluarkan respons yang menyertakan autentikasi cookie. Situs ini rentan terhadap serangan karena mempercayai permintaan apa pun yang diterimanya dengan autentikasi cookieyang valid.Pengguna mengunjungi situs berbahaya,
www.bad-crook-site.example.com.Situs berbahaya,
www.bad-crook-site.example.com, berisi formulir HTML yang mirip dengan contoh berikut:<h1>Congratulations! You're a Winner!</h1> <form action="https://www.good-banking-site.example.com/api/account" method="post"> <input type="hidden" name="Transaction" value="withdraw" /> <input type="hidden" name="Amount" value="1000000" /> <input type="submit" value="Click to collect your prize!" /> </form>Perhatikan bahwa formulir
actionmengirimkan data ke situs rentan, bukan ke situs berbahaya. Ini adalah bagian "lintas situs" dari CSRF.Pengguna memilih tombol kirim. Browser membuat permintaan dan secara otomatis menyertakan autentikasi cookie untuk domain yang diminta,
www.good-banking-site.example.com.Permintaan berjalan di
www.good-banking-site.example.comserver dengan konteks autentikasi pengguna dan dapat melakukan tindakan apa pun yang diizinkan untuk dilakukan oleh pengguna terautentikasi.
Selain skenario di mana pengguna memilih tombol untuk mengirimkan formulir, situs berbahaya dapat:
- Jalankan skrip yang secara otomatis mengirimkan formulir.
- Kirim pengiriman formulir sebagai permintaan AJAX.
- Sembunyikan formulir menggunakan CSS.
Skenario alternatif ini tidak memerlukan tindakan atau input apa pun dari pengguna selain awalnya mengunjungi situs berbahaya.
Menggunakan HTTPS tidak mencegah serangan CSRF. Situs berbahaya dapat mengirim sebuah permintaan https://www.good-banking-site.example.com/ semudah mengirim permintaan tidak aman.
Beberapa serangan menargetkan titik akhir yang merespons permintaan GET, dalam hal ini tag gambar dapat digunakan untuk melakukan tindakan. Bentuk serangan ini umum terjadi di situs forum yang mengizinkan gambar tetapi memblokir JavaScript. Aplikasi yang mengubah status pada permintaan GET, di mana variabel atau sumber daya diubah, rentan terhadap serangan berbahaya. Permintaan GET yang mengubah status tidak aman. Praktik terbaik adalah tidak pernah mengubah status pada permintaan GET.
Serangan CSRF dimungkinkan terhadap aplikasi web yang menggunakan cookie untuk autentikasi karena:
- Browser menyimpan cookie yang dikeluarkan oleh aplikasi web.
- Cookie tersimpan mencakup cookie sesi untuk pengguna yang diautentikasi.
- Browser mengirim semua cookie yang terkait dengan domain ke aplikasi web setiap permintaan terlepas dari bagaimana permintaan ke aplikasi dihasilkan dalam browser.
Namun, serangan CSRF tidak terbatas pada mengeksploitasi cookie. Misalnya, autentikasi Dasar dan Digest juga rentan. Setelah pengguna masuk dengan autentikasi Dasar atau Digest, browser secara otomatis mengirimkan kredensial pengguna hingga sesi berakhir.
Dalam konteks ini, sesi mengacu pada sesi sisi klien tempat pengguna diautentikasi. Ini tidak terkait dengan sesi sisi server atau middleware sesi ASP.NET Core.
Pengguna dapat melindungi dari kerentanan CSRF dengan mengambil tindakan pencegahan:
- Keluar dari aplikasi web setelah selesai menggunakannya.
- Hapus cookie browser secara berkala.
Namun, kerentanan CSRF pada dasarnya merupakan masalah dengan aplikasi web, bukan pengguna akhir.
Dasar-dasar autentikasi
Autentikasi berbasis Cookie adalah bentuk autentikasi yang populer. Sistem autentikasi berbasis token semakin populer, terutama untuk Aplikasi Halaman Tunggal (SPAs).
Cookie-berbasis autentikasi
Saat pengguna mengautentikasi menggunakan nama pengguna dan kata sandi mereka, mereka mengeluarkan token, yang berisi tiket autentikasi yang dapat digunakan untuk autentikasi dan otorisasi. Token disimpan sebagai cookie yang dikirim dengan setiap permintaan yang dilakukan klien. Pembuatan dan validasi cookie ini dilakukan oleh cookie middleware autentikasi. Middleware mengubah prinsipal pengguna menjadi data terenkripsi cookie. Pada permintaan berikutnya, middleware memvalidasi cookie, membuat ulang entitas utama, dan menetapkan entitas utama ke properti HttpContext.User.
Autentikasi berbasis token
Saat pengguna diautentikasi, mereka diberikan token (bukan token antiforgery). Token berisi informasi pengguna dalam bentuk klaim atau token referensi yang menunjuk aplikasi ke status pengguna yang dipertahankan di aplikasi. Saat pengguna mencoba mengakses sumber daya yang memerlukan autentikasi, token dikirim ke aplikasi dengan header otorisasi tambahan dalam bentuk Bearer token. Pendekatan ini menjadikan aplikasi tidak bergantung pada status. Dalam setiap permintaan berikutnya, token diteruskan dalam permintaan validasi sisi server. Token ini tidak dienkripsi; dikodekan. Di server, token didekodekan untuk mengakses informasinya. Untuk mengirim token pada permintaan berikutnya, simpan token di penyimpanan lokal browser. Jangan khawatir tentang kerentanan CSRF jika token disimpan di penyimpanan lokal browser. CSRF menjadi perhatian ketika token disimpan dalam cookie. Untuk informasi selengkapnya, lihat isu GitHub tentang sampel kode SPA SPA code sample adds two cookies.
Beberapa aplikasi yang dihosting di satu domain
Lingkungan hosting bersama rentan terhadap pembajakan sesi, CSRF pada saat masuk, dan serangan lainnya.
Meskipun example1.contoso.net dan example2.contoso.net merupakan host yang berbeda, ada hubungan kepercayaan implisit antara host di *.contoso.net bawah domain. Hubungan kepercayaan implisit ini memungkinkan host yang berpotensi tidak tepercaya untuk memengaruhi cookie satu sama lain (kebijakan asal yang sama yang mengatur permintaan AJAX tidak selalu berlaku untuk cookie HTTP).
Serangan yang mengeksploitasi cookie tepercaya antara aplikasi yang dihosting di domain yang sama dapat dicegah dengan tidak berbagi domain. Saat setiap aplikasi dihosting di domainnya sendiri, tidak ada hubungan kepercayaan implisit cookie untuk dieksploitasi.
konfigurasi antiforgery ASP.NET Core
Peringatan
ASP.NET Core mengimplementasikan antiforgery menggunakan ASP.NET Core Data Protection. Tumpukan perlindungan data harus dikonfigurasi untuk bekerja di farm server. Untuk informasi selengkapnya, lihat Mengonfigurasi perlindungan data.
Middleware antiforgery ditambahkan ke kontainer Injeksi Dependensi ketika salah satu API berikut dipanggil di Startup.ConfigureServices:
Dalam ASP.NET Core 2.0 atau yang lebih baru, FormTagHelper menyuntikkan token antiforgery ke dalam elemen bentuk HTML. Markup berikut dalam Razor file secara otomatis menghasilkan token antiforgery:
<form method="post">
...
</form>
Demikian pula, IHtmlHelper.BeginForm menghasilkan token antiforgery secara default jika metode formulir bukan GET.
Pembuatan otomatis token antiforgery untuk elemen formulir HTML terjadi ketika <form> tag berisi method="post" atribut dan salah satu dari yang berikut ini benar:
- Atribut tindakan kosong (
action=""). - Atribut tindakan tidak disediakan (
<form method="post">).
Pembuatan token antiforgeri otomatis untuk elemen formulir HTML dapat dinonaktifkan:
Nonaktifkan token antiforgery secara eksplisit dengan
asp-antiforgeryatribut :<form method="post" asp-antiforgery="false"> ... </form>Elemen formulir ditolak dari Pembantu Tag dengan menggunakan simbol penolakan Pembantu Tag ! :
<!form method="post"> ... </!form>Hapus
FormTagHelperdari tampilan.FormTagHelperdapat dihapus dari tampilan dengan menambahkan direktif berikut ke Razor tampilan:@removeTagHelper Microsoft.AspNetCore.Mvc.TagHelpers.FormTagHelper, Microsoft.AspNetCore.Mvc.TagHelpers
Catatan
Razor Halaman secara otomatis dilindungi dari XSRF/CSRF. Untuk informasi selengkapnya, lihat XSRF/CSRF dan Razor Pages.
Pendekatan paling umum untuk bertahan dari serangan CSRF adalah menggunakan Synchronizer Token Pattern (STP). STP digunakan saat pengguna meminta halaman dengan data formulir:
- Server mengirim token yang terkait dengan identitas pengguna saat ini ke klien.
- Klien mengirim kembali token ke server untuk verifikasi.
- Jika server menerima token yang tidak cocok dengan identitas pengguna yang diautentikasi, permintaan akan ditolak.
Token unik dan tidak dapat diprediksi. Token juga dapat digunakan untuk memastikan urutan yang tepat dari serangkaian permintaan (misalnya, memastikan urutan permintaan: halaman 1 > halaman 2 > halaman 3). Semua formulir dalam templat ASP.NET Core MVC dan Razor Pages menghasilkan token antiforgery. Contoh tampilan berikut ini menghasilkan token anti-pemalsuan:
<form asp-controller="Todo" asp-action="Create" method="post">
...
</form>
@using (Html.BeginForm("Create", "Todo"))
{
...
}
Secara eksplisit tambahkan token antiforgery ke elemen <form> tanpa menggunakan Tag Helpers dengan HTML helper @Html.AntiForgeryToken.
<form action="/" method="post">
@Html.AntiForgeryToken()
</form>
Dalam setiap kasus sebelumnya, ASP.NET Core menambahkan bidang formulir tersembunyi yang mirip dengan contoh berikut:
<input name="__RequestVerificationToken" type="hidden" value="CfDJ8NrAkS ... s2-m9Yw">
ASP.NET Core mencakup tiga filter untuk menangani token antiforgery.
Opsi anti-pemalsuan
Sesuaikan AntiforgeryOptions dalam Startup.ConfigureServices:
services.AddAntiforgery(options =>
{
options.FormFieldName = "AntiforgeryFieldname";
options.HeaderName = "X-CSRF-TOKEN-HEADERNAME";
options.SuppressXFrameOptionsHeader = false;
});
Atur properti antiforgery cookie menggunakan properti kelas CookieBuilder, seperti yang ditunjukkan dalam tabel berikut.
| Opsi | Deskripsi |
|---|---|
| Cookie | Menentukan pengaturan yang digunakan untuk membuat cookie antiforgery. |
| FormFieldName | Nama kolom formulir tersembunyi yang digunakan oleh sistem antiforgery untuk memproses token antiforgery dalam tampilan. |
| HeaderName | Nama header yang digunakan oleh sistem anti-pemalsuan. Jika null, sistem hanya mempertimbangkan data formulir. |
| SuppressXFrameOptionsHeader | Menentukan apakah akan mengabaikan pembuatan header X-Frame-Options. Secara default, header dihasilkan dengan nilai "SAMEORIGIN". Bawaan ke false. |
Beberapa browser tidak mengizinkan titik akhir yang tidak aman untuk mengatur cookie dengan flag 'secure' atau menimpa cookie yang flag 'secure'-nya sudah diatur (untuk informasi selengkapnya, lihat Menyarankan untuk tidak memodifikasi cookie 'secure' dari asal yang tidak aman). Karena mencampur titik akhir yang aman dan tidak aman adalah skenario umum dalam aplikasi, ASP.NET Core melonggarkan pembatasan pada kebijakan aman pada beberapa cookie, seperti antiforgery cookie, dengan mengatur cookie dari SecurePolicy ke CookieSecurePolicy.None. Bahkan jika pengguna berbahaya mencuri antiforgery cookie, mereka juga harus mencuri token antiforgery yang biasanya dikirim melalui bidang formulir (lebih umum) atau header permintaan terpisah (kurang umum) ditambah autentikasi cookie.
Cookies terkait dengan autentikasi atau otorisasi menggunakan kebijakan yang lebih kuat daripada CookieSecurePolicy.None.
Secara opsional, Anda dapat mengamankan antiforgery cookie di lingkungan non-Development menggunakan Secure Sockets Layer (SSL), hanya melalui HTTPS, dengan pengaturan properti berikut AntiforgeryOptions.Cookie di kelas Startup aplikasi:
public class Startup
{
public Startup(IConfiguration configuration, IHostEnvironment environment)
{
Configuration = configuration;
Environment = environment;
}
public IConfiguration Configuration { get; }
public IHostEnvironment Environment { get; }
public void ConfigureServices(IServiceCollection services)
{
// Other services are registered here
if (!Environment.IsDevelopment())
{
services.AddAntiforgery(o =>
{
o.Cookie.SecurePolicy = CookieSecurePolicy.Always;
});
}
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
// Request processing pipeline
}
}
Untuk informasi selengkapnya, lihat CookieAuthenticationOptions .
Mengonfigurasi fitur antiforgery dengan IAntiforgery
IAntiforgery menyediakan API untuk mengonfigurasi fitur antiforgery.
IAntiforgery dapat diminta dalam metode Configure di kelas Startup.
Dalam contoh berikut:
- Middleware dari halaman utama aplikasi digunakan untuk menghasilkan token antiforgery dan mengirimkannya dalam respons sebagai cookie.
- Token permintaan dikirim sebagai JavaScript-readable cookie dengan konvensi penamaan Angular default yang dijelaskan di bagian AngularJS .
public void Configure(IApplicationBuilder app, IAntiforgery antiforgery)
{
app.Use(next => context =>
{
string path = context.Request.Path.Value;
if (string.Equals(path, "/", StringComparison.OrdinalIgnoreCase) ||
string.Equals(path, "/index.html", StringComparison.OrdinalIgnoreCase))
{
var tokens = antiforgery.GetAndStoreTokens(context);
context.Response.Cookies.Append("XSRF-TOKEN", tokens.RequestToken,
new CookieOptions() { HttpOnly = false });
}
return next(context);
});
}
Memerlukan validasi pencegahan pemalsuan
ValidateAntiForgeryToken adalah filter tindakan yang dapat diterapkan ke tindakan individual, pengontrol, atau secara global. Permintaan yang dibuat untuk tindakan yang menerapkan filter ini diblokir kecuali permintaan menyertakan token antiforgery yang valid.
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> RemoveLogin(RemoveLoginViewModel account)
{
ManageMessageId? message = ManageMessageId.Error;
var user = await GetCurrentUserAsync();
if (user != null)
{
var result =
await _userManager.RemoveLoginAsync(
user, account.LoginProvider, account.ProviderKey);
if (result.Succeeded)
{
await _signInManager.SignInAsync(user, isPersistent: false);
message = ManageMessageId.RemoveLoginSuccess;
}
}
return RedirectToAction(nameof(ManageLogins), new { Message = message });
}
Atribut ValidateAntiForgeryToken memerlukan token untuk permintaan ke metode tindakan yang ditandainya, termasuk permintaan HTTP GET. Jika atribut ValidateAntiForgeryToken diterapkan di seluruh pengontrol aplikasi, atribut tersebut dapat ditimpa dengan atribut IgnoreAntiforgeryToken.
Catatan
ASP.NET Core tidak mendukung penambahan token antiforgery ke permintaan GET secara otomatis.
Memvalidasi secara otomatis token antiforgery hanya untuk metode HTTP yang dianggap tidak aman.
Aplikasi ASP.NET Core tidak menghasilkan token antiforgery untuk metode HTTP yang aman (GET, HEAD, OPTIONS, dan TRACE). Alih-alih menerapkan atribut ValidateAntiForgeryToken secara luas dan kemudian menimpanya dengan atribut IgnoreAntiforgeryToken, atribut AutoValidateAntiforgeryToken dapat digunakan. Atribut ini berfungsi secara identik dengan ValidateAntiForgeryToken atribut , kecuali bahwa atribut ini tidak memerlukan token untuk permintaan yang dibuat menggunakan metode HTTP berikut:
- DAPATKAN
- Kepala
- OPSI
- TRACE
Sebaiknya gunakan AutoValidateAntiforgeryToken secara luas untuk skenario non-API. Atribut ini memastikan tindakan POST dilindungi secara default. Alternatifnya adalah mengabaikan token antiforgery secara default, kecuali ValidateAntiForgeryToken diterapkan ke metode tindakan individual. Dalam skenario ini, lebih mungkin metode tindakan POST dibiarkan tidak terlindungi secara tidak sengaja, membuat aplikasi rentan terhadap serangan CSRF. Semua POS harus mengirim token antiforgery.
API tidak memiliki mekanisme otomatis untuk mengirimkan bagian dari token yang bukan cookie. Implementasi mungkin tergantung pada implementasi kode klien. Beberapa contoh ditunjukkan di bawah ini:
Contoh pada tingkat kelas:
[Authorize]
[AutoValidateAntiforgeryToken]
public class ManageController : Controller
{
Contoh global:
services.AddControllersWithViews(options =>
options.Filters.Add(new AutoValidateAntiforgeryTokenAttribute()));
Mengambil alih atribut antiforgery global atau pengontrol
Filter IgnoreAntiforgeryToken digunakan untuk menghilangkan kebutuhan token antiforgery untuk tindakan tertentu (atau pengontrol). Ketika diterapkan, filter ini akan mengesampingkan filter ValidateAntiForgeryToken dan AutoValidateAntiforgeryToken yang ditentukan pada tingkat yang lebih tinggi (secara global atau pada pengontrol).
[Authorize]
[AutoValidateAntiforgeryToken]
public class ManageController : Controller
{
[HttpPost]
[IgnoreAntiforgeryToken]
public async Task<IActionResult> DoSomethingSafe(SomeViewModel model)
{
// no antiforgery token required
}
}
Penyegaran token setelah autentikasi
Token harus di-refresh setelah pengguna diautentikasi dengan mengalihkan pengguna ke halaman tampilan atau Razor Halaman.
JavaScript, AJAX, dan SPAs
Dalam aplikasi tradisional berbasis HTML, token antiforgery dikirimkan ke server menggunakan kolom formulir tersembunyi. Di aplikasi dan SPAs berbasis JavaScript modern, banyak permintaan dibuat secara terprogram. Permintaan AJAX ini dapat menggunakan teknik lain (seperti header permintaan atau cookie) untuk mengirim token.
Jika cookie digunakan untuk menyimpan token autentikasi dan untuk mengautentikasi permintaan API di server, CSRF adalah masalah potensial. Jika penyimpanan lokal digunakan untuk menyimpan token, kerentanan CSRF mungkin dimitigasi karena nilai dari penyimpanan lokal tidak dikirim secara otomatis ke server dengan setiap permintaan. Menggunakan penyimpanan lokal untuk menyimpan token antiforgery pada klien dan mengirim token sebagai header permintaan adalah pendekatan yang direkomendasikan.
JavaScript
Dengan menggunakan JavaScript pada tampilan, token dapat dibuat menggunakan layanan dari dalam tampilan tersebut. IAntiforgery Masukkan layanan ke dalam tampilan dan panggil GetAndStoreTokens:
@{
ViewData["Title"] = "AJAX Demo";
}
@inject Microsoft.AspNetCore.Antiforgery.IAntiforgery Xsrf
@functions{
public string GetAntiXsrfRequestToken()
{
return Xsrf.GetAndStoreTokens(Context).RequestToken;
}
}
<input type="hidden" id="RequestVerificationToken"
name="RequestVerificationToken" value="@GetAntiXsrfRequestToken()">
<h2>@ViewData["Title"].</h2>
<h3>@ViewData["Message"]</h3>
<div class="row">
<p><input type="button" id="antiforgery" value="Antiforgery"></p>
<script>
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (xhttp.readyState == XMLHttpRequest.DONE) {
if (xhttp.status == 200) {
alert(xhttp.responseText);
} else {
alert('There was an error processing the AJAX request.');
}
}
};
document.addEventListener('DOMContentLoaded', function() {
document.getElementById("antiforgery").onclick = function () {
xhttp.open('POST', '@Url.Action("Antiforgery", "Home")', true);
xhttp.setRequestHeader("RequestVerificationToken",
document.getElementById('RequestVerificationToken').value);
xhttp.send();
}
});
</script>
</div>
Pendekatan ini menghilangkan kebutuhan untuk berurusan langsung dengan pengaturan cookie dari server atau membacanya dari klien.
Contoh sebelumnya menggunakan JavaScript untuk membaca nilai bidang tersembunyi untuk header AJAX POST.
JavaScript dapat mengakses token dalam cookie dan menggunakan konten dari cookie untuk membuat header dengan nilai token tersebut.
context.Response.Cookies.Append("CSRF-TOKEN", tokens.RequestToken,
new Microsoft.AspNetCore.Http.CookieOptions { HttpOnly = false });
Dengan asumsi permintaan skrip mengirim token di header yang disebut X-CSRF-TOKEN, konfigurasikan layanan antiforgery agar mencari dalam header X-CSRF-TOKEN.
services.AddAntiforgery(options => options.HeaderName = "X-CSRF-TOKEN");
Contoh berikut menggunakan JavaScript untuk membuat permintaan AJAX dengan header yang sesuai:
function getCookie(cname) {
var name = cname + "=";
var decodedCookie = decodeURIComponent(document.cookie);
var ca = decodedCookie.split(';');
for (var i = 0; i < ca.length; i++) {
var c = ca[i];
while (c.charAt(0) === ' ') {
c = c.substring(1);
}
if (c.indexOf(name) === 0) {
return c.substring(name.length, c.length);
}
}
return "";
}
var csrfToken = getCookie("CSRF-TOKEN");
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function () {
if (xhttp.readyState === XMLHttpRequest.DONE) {
if (xhttp.status === 204) {
alert('Todo item is created successfully.');
} else {
alert('There was an error processing the AJAX request.');
}
}
};
xhttp.open('POST', '/api/items', true);
xhttp.setRequestHeader("Content-type", "application/json");
xhttp.setRequestHeader("X-CSRF-TOKEN", csrfToken);
xhttp.send(JSON.stringify({ "name": "Learn C#" }));
AngularJS
AngularJS menggunakan konvensi untuk mengatasi CSRF. Jika server mengirim cookie dengan nama XSRF-TOKEN, layanan AngularJS $http menambahkan cookie nilai ke header saat mengirim permintaan ke server. Proses ini bersifat otomatis. Klien tidak perlu mengatur header secara eksplisit. Nama header adalah X-XSRF-TOKEN. Server harus mendeteksi header ini dan memvalidasi isinya.
Agar ASP.NET Core API berfungsi dengan konvensi ini dalam startup aplikasi Anda:
- Konfigurasikan aplikasi Anda untuk menyediakan token dalam sebuah cookie yang disebut
XSRF-TOKEN. - Konfigurasikan layanan antiforgery untuk mencari header bernama
X-XSRF-TOKEN, yang merupakan nama header default Angular untuk mengirim token XSRF.
public void Configure(IApplicationBuilder app, IAntiforgery antiforgery)
{
app.Use(next => context =>
{
string path = context.Request.Path.Value;
if (
string.Equals(path, "/", StringComparison.OrdinalIgnoreCase) ||
string.Equals(path, "/index.html", StringComparison.OrdinalIgnoreCase))
{
var tokens = antiforgery.GetAndStoreTokens(context);
context.Response.Cookies.Append("XSRF-TOKEN", tokens.RequestToken,
new CookieOptions() { HttpOnly = false });
}
return next(context);
});
}
public void ConfigureServices(IServiceCollection services)
{
services.AddAntiforgery(options => options.HeaderName = "X-XSRF-TOKEN");
}
Catatan
Ketika token antiforgery disediakan di header permintaan dan dalam payload formulir, hanya token di header yang divalidasi.
Autentikasi Windows dan kuki anti-pemalsuan
Saat menggunakan Autentikasi Windows, titik akhir aplikasi harus dilindungi dari serangan CSRF dengan cara yang sama seperti yang dilakukan untuk cookie. Browser secara implisit mengirim konteks autentikasi ke server sehingga titik akhir perlu dilindungi dari serangan CSRF.
Perluas fitur anti-pemalsuan
Jenis ini IAntiforgeryAdditionalDataProvider memungkinkan pengembang untuk memperpanjang fungsi sistem anti-CSRF dengan memutar alihkan data tambahan di setiap token. Metode GetAdditionalData ini dipanggil setiap kali token bidang dihasilkan, dan nilai pengembalian disematkan dalam token yang dihasilkan. Pelaksana dapat mengembalikan tanda waktu, nonce, atau nilai lain lalu memanggil ValidateAdditionalData untuk memvalidasi data ini saat token divalidasi. Nama pengguna klien sudah disematkan dalam token yang dihasilkan, sehingga tidak perlu menyertakan informasi ini. Jika token menyertakan data tambahan tetapi tidak IAntiForgeryAdditionalDataProvider dikonfigurasi, data tambahan tidak divalidasi.
Sumber Daya Tambahan:
ASP.NET Core