Mencegah serangan Pemalsuan Permintaan Lintas Situs (XSRF/CSRF) di ASP.NET Core
Oleh Fiyaz Hasan, Rick Anderson, dan Steve Smith
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 satu klik atau naik sesi karena serangan memanfaatkan sesi pengguna yang sebelumnya diautentikasi.
Contoh serangan CSRF:
Pengguna masuk
www.good-banking-site.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.com.Situs berbahaya,
www.bad-crook-site.com, berisi formulir HTML yang mirip dengan contoh berikut:<h1>Congratulations! You're a Winner!</h1> <form action="https://good-banking-site.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 posting formulir
actionke situs yang 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.com.Permintaan berjalan di
www.good-banking-site.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 https://www.good-banking-site.com/ permintaan semudah dapat mengirim permintaan yang 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 pada 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 cookies untuk autentikasi karena:
- Browser menyimpan cookieyang dikeluarkan oleh aplikasi web.
- S tersimpan cookiemencakup sesi cookieuntuk pengguna yang diautentikasi.
- Browser mengirim semua cookieyang terkait dengan domain ke aplikasi web setiap permintaan terlepas dari bagaimana permintaan ke aplikasi dihasilkan dalam browser.
Namun, serangan CSRF tidak terbatas pada eksploitasi cookie. Misalnya, autentikasi Dasar dan Hash juga rentan. Setelah pengguna masuk dengan autentikasi Dasar atau Hash, browser secara otomatis mengirim kredensial hingga sesi berakhir.
Dalam konteks ini, sesi mengacu pada sesi sisi klien tempat pengguna diautentikasi. Ini tidak terkait dengan sesi sisi server atau ASP.NET Middleware Sesi Inti.
Pengguna dapat melindungi dari kerentanan CSRF dengan mengambil tindakan pencegahan:
- Keluar dari aplikasi web setelah selesai menggunakannya.
- Hapus browser cookiesecara berkala.
Namun, kerentanan CSRF pada dasarnya merupakan masalah dengan aplikasi web, bukan pengguna akhir.
Dasar-dasar autentikasi
CookieAutentikasi berbasis -adalah bentuk autentikasi yang populer. Sistem autentikasi berbasis token semakin populer, terutama untuk Aplikasi Halaman Tunggal (SPAs).
CookieAutentikasi berbasis-
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 yang dikirim dengan setiap permintaan yang cookie dilakukan klien. Membuat dan memvalidasi ini cookie dilakukan oleh Cookie Middleware Autentikasi. Middleware menserialisasikan prinsipal pengguna ke dalam terenkripsicookie. Pada permintaan berikutnya, middleware memvalidasi cookie, membuat ulang prinsipal, dan menetapkan utama ke HttpContext.User properti .
Autentikasi berbasis token
Saat pengguna diautentikasi, mereka mengeluarkan token (bukan token antiforgery). Token berisi informasi pengguna dalam bentuk klaim atau token referensi yang menunjuk aplikasi ke status pengguna yang dipertahankan di aplikasi. Ketika pengguna mencoba mengakses sumber daya yang memerlukan autentikasi, token dikirim ke aplikasi dengan header otorisasi tambahan dalam bentuk token Pembawa. Pendekatan ini membuat aplikasi tanpa status. Dalam setiap permintaan berikutnya, token diteruskan dalam permintaan untuk validasi sisi server. Token ini tidak dienkripsi; itu dikodekan. Di server, token didekode 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 sampel kode SPA masalah GitHub menambahkan dua cookies.
Beberapa aplikasi yang dihosting di satu domain
Lingkungan hosting bersama rentan terhadap pembajakan sesi, CSRF 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 mempengaruhi satu sama lain cookie(kebijakan asal yang sama yang mengatur permintaan AJAX tidak selalu berlaku untuk HTTP cookie.
Serangan yang mengeksploitasi cookietepercaya 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.
Antiforgeri dalam ASP.NET Core
Peringatan
ASP.NET Core menerapkan antiforgeri 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 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 hal berikut ini benar:
- Atribut tindakan kosong (
action=""). - Atribut tindakan tidak disediakan (
<form method="post">).
Pembuatan otomatis token antiforgery 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 Tag Helper ! :
<!form method="post"> <!-- ... --> </!form>FormTagHelperHapus dari 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 Halaman.
Pendekatan paling umum untuk bertahan dari serangan CSRF adalah menggunakan Pola Token Penyinkron (STP). STP digunakan saat pengguna meminta halaman dengan data formulir:
- Server mengirimkan 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 pasangan berikut menghasilkan token antiforgery:
<form asp-action="Index" asp-controller="Home" method="post">
<!-- ... -->
</form>
@using (Html.BeginForm("Index", "Home"))
{
<!-- ... -->
}
Secara eksplisit menambahkan token antiforgeri ke <form> elemen tanpa menggunakan Pembantu Tag dengan pembantu HTML @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 menyertakan tiga filter untuk bekerja dengan token antiforgery:
Antiforgery dengan AddControllers
AddControllers Panggilan tidak mengaktifkan token antiforgery. AddControllersWithViews harus dipanggil untuk memiliki dukungan token antiforgery bawaan.
Beberapa tab browser dan Pola Token Penyinkron
Dengan Pola Token Penyinkron, hanya halaman yang terakhir 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 antiforgery dengan AntiforgeryOptions
Sesuaikan AntiforgeryOptions di Program.cs:
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 , seperti yang CookieBuilder ditunjukkan dalam tabel berikut.
| Opsi | Deskripsi |
|---|---|
| Cookie | Menentukan pengaturan yang digunakan untuk membuat antiforgeri cookie. |
| FormFieldName | Nama bidang formulir tersembunyi yang digunakan oleh sistem antiforgeri untuk merender token antiforgery dalam tampilan. |
| HeaderName | Nama header yang digunakan oleh sistem antiforgery. Jika null, sistem hanya mempertimbangkan data formulir. |
| SuppressXFrameOptionsHeader | Menentukan apakah akan menekan pembuatan X-Frame-Options header. Secara default, header dihasilkan dengan nilai "SAMEORIGIN". Default ke false. |
Untuk informasi selengkapnya, lihat CookieAuthenticationOptions.
Hasilkan token antiforgery dengan IAntiforgery
IAntiforgery menyediakan API untuk mengonfigurasi fitur antiforgery. IAntiforgery dapat diminta dalam Program.cs menggunakan WebApplication.Services. Contoh berikut menggunakan middleware dari halaman beranda 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 bernama cookieXSRF-TOKEN. Klien dapat membaca ini cookie dan memberikan nilainya sebagai header yang dilampirkan ke permintaan AJAX. Misalnya, Angular menyertakan perlindungan XSRF bawaan yang membaca bernama cookieXSRF-TOKEN secara default.
Memerlukan validasi antiforgery
Filter tindakan ValidateAntiForgeryToken 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 IActionResult Index()
{
// ...
return RedirectToAction();
}
Atribut ValidateAntiForgeryToken memerlukan token untuk permintaan ke metode tindakan yang ditandainya, termasuk permintaan HTTP GET. ValidateAntiForgeryToken Jika atribut diterapkan di seluruh pengontrol aplikasi, atribut dapat ditimpa dengan IgnoreAntiforgeryToken atribut .
Memvalidasi token antiforgery secara otomatis hanya untuk metode HTTP yang tidak aman
Alih-alih menerapkan ValidateAntiForgeryToken atribut secara luas dan kemudian menimpanya dengan IgnoreAntiforgeryToken atribut, 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:
- GET
- KEPALA
- OPTIONS
- JEJAK
Kami merekomendasikan penggunaan 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. Lebih mungkin dalam skenario ini untuk 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 mengirim bagian non-tokencookie . Implementasi mungkin tergantung pada implementasi kode klien. Beberapa contoh ditunjukkan di bawah ini:
Contoh 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 akan token antiforgery untuk tindakan tertentu (atau pengontrol). Saat diterapkan, filter ini mengambil alih ValidateAntiForgeryToken dan AutoValidateAntiforgeryToken filter yang ditentukan pada tingkat yang lebih tinggi (secara global atau pada pengontrol).
[IgnoreAntiforgeryToken]
public IActionResult IndexOverride()
{
// ...
return RedirectToAction();
}
Refresh 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 diteruskan ke server menggunakan bidang formulir tersembunyi. Dalam aplikasi dan SPAs berbasis JavaScript modern, banyak permintaan dibuat secara terprogram. Permintaan AJAX ini dapat menggunakan teknik lain (seperti header permintaan atau cookies) untuk mengirim token.
Jika cookies 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
Menggunakan JavaScript dengan tampilan, token dapat dibuat menggunakan layanan dari dalam tampilan. IAntiforgery Masukkan layanan ke 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>
}
Pendekatan ini menghilangkan kebutuhan untuk berurusan langsung dengan pengaturan cookies dari server atau membacanya dari klien.
Contoh sebelumnya menggunakan JavaScript untuk membaca nilai bidang tersembunyi untuk header AJAX POST.
JavaScript juga dapat mengakses token dalam cookiedan menggunakan cookiekonten 's untuk membuat header dengan nilai token. Contoh berikut menulis token permintaan ke JavaScript yang dapat cookiedibaca :
context.Response.Cookies.Append("XSRF-TOKEN", tokenSet.RequestToken!,
new CookieOptions { HttpOnly = false });
Dengan asumsi skrip mengirim token di header permintaan yang disebut X-XSRF-TOKEN, konfigurasikan layanan antiforgery untuk X-XSRF-TOKEN mencari header:
builder.Services.AddAntiforgery(options => options.HeaderName = "X-XSRF-TOKEN");
Contoh berikut menggunakan JavaScript untuk membuat permintaan AJAX dengan header yang sesuai:
// https://developer.mozilla.org/en-US/docs/web/api/document/cookie
const xsrfToken = document.cookie
.split("; ")
.find(row => row.startsWith("XSRF-TOKEN="))
.split("=")[1];
const response = await fetch("/JavaScript/FetchEndpoint", {
method: "POST",
headers: { "X-XSRF-TOKEN": xsrfToken }
});
if (response.ok) {
resultElement.innerText = await response.text();
} else {
resultElement.innerText = `Request Failed: ${response.status}`
}
Autentikasi Windows dan antiforgeri cookie
Saat menggunakan Autentikasi Windows, titik akhir aplikasi harus dilindungi dari serangan CSRF dengan cara yang sama seperti yang dilakukan untuk cookies. Browser secara implisit mengirim konteks autentikasi ke server sehingga titik akhir perlu dilindungi dari serangan CSRF.
Memperpanjang antiforgeri
Jenis ini IAntiforgeryAdditionalDataProvider memungkinkan pengembang untuk memperluas perilaku sistem anti-CSRF dengan melakukan round-tripping data tambahan di setiap token. Metode GetAdditionalData ini dipanggil setiap kali token bidang dihasilkan, dan nilai yang dikembalikan disematkan dalam token yang dihasilkan. Pelaksana dapat mengembalikan tanda waktu, nonce, atau nilai lainnya 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 satu klik atau naik sesi karena serangan memanfaatkan sesi pengguna yang sebelumnya diautentikasi.
Contoh serangan CSRF:
Pengguna masuk
www.good-banking-site.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.com.Situs berbahaya,
www.bad-crook-site.com, berisi formulir HTML yang mirip dengan contoh berikut:<h1>Congratulations! You're a Winner!</h1> <form action="https://good-banking-site.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 posting formulir
actionke situs yang 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.com.Permintaan berjalan di
www.good-banking-site.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 https://www.good-banking-site.com/ permintaan semudah dapat mengirim permintaan yang 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 pada 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 cookies untuk autentikasi karena:
- Browser menyimpan cookieyang dikeluarkan oleh aplikasi web.
- S tersimpan cookiemencakup sesi cookieuntuk pengguna yang diautentikasi.
- Browser mengirim semua cookieyang terkait dengan domain ke aplikasi web setiap permintaan terlepas dari bagaimana permintaan ke aplikasi dihasilkan dalam browser.
Namun, serangan CSRF tidak terbatas pada eksploitasi cookie. Misalnya, autentikasi Dasar dan Hash juga rentan. Setelah pengguna masuk dengan autentikasi Dasar atau Hash, browser secara otomatis mengirim kredensial hingga sesi berakhir.
Dalam konteks ini, sesi mengacu pada sesi sisi klien tempat pengguna diautentikasi. Ini tidak terkait dengan sesi sisi server atau ASP.NET Middleware Sesi Inti.
Pengguna dapat melindungi dari kerentanan CSRF dengan mengambil tindakan pencegahan:
- Keluar dari aplikasi web setelah selesai menggunakannya.
- Hapus browser cookiesecara berkala.
Namun, kerentanan CSRF pada dasarnya merupakan masalah dengan aplikasi web, bukan pengguna akhir.
Dasar-dasar autentikasi
CookieAutentikasi berbasis -adalah bentuk autentikasi yang populer. Sistem autentikasi berbasis token semakin populer, terutama untuk Aplikasi Halaman Tunggal (SPAs).
CookieAutentikasi berbasis-
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 yang dikirim dengan setiap permintaan yang cookie dilakukan klien. Membuat dan memvalidasi ini cookie dilakukan oleh Cookie Middleware Autentikasi. Middleware menserialisasikan prinsipal pengguna ke dalam terenkripsicookie. Pada permintaan berikutnya, middleware memvalidasi cookie, membuat ulang prinsipal, dan menetapkan utama ke HttpContext.User properti .
Autentikasi berbasis token
Saat pengguna diautentikasi, mereka mengeluarkan token (bukan token antiforgery). Token berisi informasi pengguna dalam bentuk klaim atau token referensi yang menunjuk aplikasi ke status pengguna yang dipertahankan di aplikasi. Ketika pengguna mencoba mengakses sumber daya yang memerlukan autentikasi, token dikirim ke aplikasi dengan header otorisasi tambahan dalam bentuk token Pembawa. Pendekatan ini membuat aplikasi tanpa status. Dalam setiap permintaan berikutnya, token diteruskan dalam permintaan untuk validasi sisi server. Token ini tidak dienkripsi; itu dikodekan. Di server, token didekode 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 sampel kode SPA masalah GitHub menambahkan dua cookies.
Beberapa aplikasi yang dihosting di satu domain
Lingkungan hosting bersama rentan terhadap pembajakan sesi, CSRF 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 mempengaruhi satu sama lain cookie(kebijakan asal yang sama yang mengatur permintaan AJAX tidak selalu berlaku untuk HTTP cookie.
Serangan yang mengeksploitasi cookietepercaya 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 antiforgeri ASP.NET Core
Peringatan
ASP.NET Core menerapkan antiforgeri 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 hal berikut ini benar:
- Atribut tindakan kosong (
action=""). - Atribut tindakan tidak disediakan (
<form method="post">).
Pembuatan otomatis token antiforgery 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 Tag Helper ! :
<!form method="post"> ... </!form>FormTagHelperHapus dari 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 Halaman.
Pendekatan paling umum untuk bertahan dari serangan CSRF adalah menggunakan Pola Token Penyinkron (STP). STP digunakan saat pengguna meminta halaman dengan data formulir:
- Server mengirimkan 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 pasangan berikut menghasilkan token antiforgery:
<form asp-controller="Todo" asp-action="Create" method="post">
...
</form>
@using (Html.BeginForm("Create", "Todo"))
{
...
}
Secara eksplisit menambahkan token antiforgeri ke <form> elemen tanpa menggunakan Pembantu Tag dengan pembantu HTML @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 menyertakan tiga filter untuk bekerja dengan token antiforgery:
Opsi antiforgery
Sesuaikan AntiforgeryOptions di Startup.ConfigureServices:
services.AddAntiforgery(options =>
{
options.FormFieldName = "AntiforgeryFieldname";
options.HeaderName = "X-CSRF-TOKEN-HEADERNAME";
options.SuppressXFrameOptionsHeader = false;
});
Atur properti antiforgery Cookie menggunakan properti kelas , seperti yang CookieBuilder ditunjukkan dalam tabel berikut.
| Opsi | Deskripsi |
|---|---|
| Cookie | Menentukan pengaturan yang digunakan untuk membuat antiforgeri cookie. |
| FormFieldName | Nama bidang formulir tersembunyi yang digunakan oleh sistem antiforgeri untuk merender token antiforgery dalam tampilan. |
| HeaderName | Nama header yang digunakan oleh sistem antiforgery. Jika null, sistem hanya mempertimbangkan data formulir. |
| SuppressXFrameOptionsHeader | Menentukan apakah akan menekan pembuatan X-Frame-Options header. Secara default, header dihasilkan dengan nilai "SAMEORIGIN". Default ke false. |
Untuk informasi selengkapnya, lihat CookieAuthenticationOptions.
Mengonfigurasi fitur antiforgery dengan IAntiforgery
IAntiforgery menyediakan API untuk mengonfigurasi fitur antiforgery. IAntiforgery dapat diminta dalam Configure metode Startup kelas .
Lihat contoh berikut:
- Middleware dari halaman beranda aplikasi digunakan untuk menghasilkan token antiforgery dan mengirimkannya dalam respons sebagai cookie.
- Token permintaan dikirim sebagai JavaScript yang dapat cookie dibaca 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 antiforgery
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. ValidateAntiForgeryToken Jika atribut diterapkan di seluruh pengontrol aplikasi, atribut dapat ditimpa dengan IgnoreAntiforgeryToken atribut .
Catatan
ASP.NET Core tidak mendukung penambahan token antiforgery ke permintaan GET secara otomatis.
Memvalidasi token antiforgery secara otomatis hanya untuk metode HTTP yang tidak aman
ASP.NET Aplikasi inti tidak menghasilkan token antiforgeri untuk metode HTTP yang aman (GET, HEAD, OPTIONS, dan TRACE). Alih-alih menerapkan ValidateAntiForgeryToken atribut secara luas dan kemudian menimpanya dengan IgnoreAntiforgeryToken atribut, 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:
- GET
- KEPALA
- OPTIONS
- JEJAK
Kami merekomendasikan penggunaan 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. Lebih mungkin dalam skenario ini untuk 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 mengirim bagian non-tokencookie . Implementasi mungkin tergantung pada implementasi kode klien. Beberapa contoh ditunjukkan di bawah ini:
Contoh 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 akan token antiforgery untuk tindakan tertentu (atau pengontrol). Saat diterapkan, filter ini mengambil alih ValidateAntiForgeryToken dan AutoValidateAntiforgeryToken filter 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
}
}
Refresh 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 diteruskan ke server menggunakan bidang formulir tersembunyi. Dalam aplikasi dan SPAs berbasis JavaScript modern, banyak permintaan dibuat secara terprogram. Permintaan AJAX ini dapat menggunakan teknik lain (seperti header permintaan atau cookies) untuk mengirim token.
Jika cookies 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
Menggunakan JavaScript dengan tampilan, token dapat dibuat menggunakan layanan dari dalam tampilan. IAntiforgery Masukkan layanan ke 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 cookies dari server atau membacanya dari klien.
Contoh sebelumnya menggunakan JavaScript untuk membaca nilai bidang tersembunyi untuk header AJAX POST.
JavaScript juga dapat mengakses token dalam cookiedan menggunakan cookiekonten 's untuk membuat header dengan nilai token.
context.Response.Cookies.Append("CSRF-TOKEN", tokens.RequestToken,
new Microsoft.AspNetCore.Http.CookieOptions { HttpOnly = false });
Dengan asumsi permintaan skrip untuk mengirim token di header yang disebut X-CSRF-TOKEN, konfigurasikan layanan antiforgery untuk X-CSRF-TOKEN mencari header:
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#" }));
SudutJS
JS Angular 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 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 yang cookie 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");
}
Autentikasi Windows dan antiforgeri cookie
Saat menggunakan Autentikasi Windows, titik akhir aplikasi harus dilindungi dari serangan CSRF dengan cara yang sama seperti yang dilakukan untuk cookies. Browser secara implisit mengirim konteks autentikasi ke server sehingga titik akhir perlu dilindungi dari serangan CSRF.
Memperpanjang antiforgeri
Jenis ini IAntiforgeryAdditionalDataProvider memungkinkan pengembang untuk memperluas perilaku sistem anti-CSRF dengan melakukan round-tripping data tambahan di setiap token. Metode GetAdditionalData ini dipanggil setiap kali token bidang dihasilkan, dan nilai yang dikembalikan disematkan dalam token yang dihasilkan. Pelaksana dapat mengembalikan tanda waktu, nonce, atau nilai lainnya 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.