Bagikan melalui


Pencegahan XSRF/CSRF di ASP.NET MVC dan Halaman Web

oleh Rick Anderson

Pemalsuan permintaan lintas situs (juga dikenal sebagai XSRF atau CSRF) adalah serangan terhadap aplikasi yang dihosting web di mana situs web berbahaya dapat memengaruhi interaksi antara browser klien dan situs web yang dipercaya oleh browser tersebut. Serangan ini dimungkinkan karena browser web akan mengirim token autentikasi secara otomatis dengan setiap permintaan ke situs web. Contoh kanonis adalah cookie autentikasi, seperti ASP. Tiket Autentikasi Formulir NET. Namun, situs web yang menggunakan mekanisme autentikasi persisten apa pun (seperti Autentikasi Windows, Dasar, dan sebagainya) dapat ditargetkan oleh serangan ini.

Serangan XSRF berbeda dari serangan phishing. Serangan pengelabuan membutuhkan interaksi dari korban. Dalam serangan phishing, situs web berbahaya akan meniru situs web target, dan korban dibodohi untuk memberikan informasi sensitif kepada penyerang. Dalam serangan XSRF, sering kali tidak ada interaksi yang diperlukan dari korban. Sebaliknya, penyerang mengandalkan browser secara otomatis mengirim semua cookie yang relevan ke situs web tujuan.

Untuk informasi selengkapnya, lihat Open Web Application Security Project (OWASP) XSRF.

Anatomi serangan

Untuk menelusuri serangan XSRF, pertimbangkan pengguna yang ingin melakukan beberapa transaksi perbankan online. Pengguna ini pertama kali mengunjungi WoodgroveBank.com dan masuk, di mana header respons akan berisi cookie autentikasinya:

HTTP/1.1 200 OK
Date: Mon, 18 Jun 2012 21:22:33 GMT
X-AspNet-Version: 4.0.30319
Set-Cookie: .ASPXAUTH={authentication-token}; path=/; secure; HttpOnly;
{ Cache-Control, Content-Type, Location, Server and other keys/values not listed. }

Karena cookie autentikasi adalah cookie sesi, cookie akan secara otomatis dihapus oleh browser ketika proses browser keluar. Namun, sampai saat itu, browser akan secara otomatis menyertakan cookie dengan setiap permintaan untuk WoodgroveBank.com. Pengguna sekarang ingin mentransfer $ 1000 ke akun lain, jadi dia mengisi formulir di situs perbankan, dan browser membuat permintaan ini ke server:

POST /DoTransfer HTTP/1.1
Host: WoodgroveBank.com
Content-Type: application/x-www-form-urlencoded
Cookie: .ASPXAUTH={authentication-token}
toAcct=12345&amount=1,000.00

Karena operasi ini memiliki efek samping (memulai transaksi moneter), situs perbankan telah memilih untuk mewajibkan HTTP POST untuk memulai operasi ini. Server membaca token autentikasi dari permintaan, mencari nomor rekening pengguna saat ini, memverifikasi bahwa ada dana yang memadai, lalu memulai transaksi ke akun tujuan.

Perbankan onlinenya selesai, pengguna menavigasi jauh dari situs perbankan dan mengunjungi lokasi lain di web. Salah satu situs tersebut - fabrikam.com - mencakup markup berikut pada halaman yang disematkan dalam <iframe>:

<form id="theForm" action="https://WoodgroveBank.com/DoTransfer" method="post">
    <input type="hidden" name="toAcct" value="67890" />
    <input type="hidden" name="amount" value="250.00" />
</form>
<script type="text/javascript">
    document.getElementById('theForm').submit();
</script>

Yang kemudian menyebabkan browser membuat permintaan ini:

POST /DoTransfer HTTP/1.1
Host: WoodgroveBank.com
Content-Type: application/x-www-form-urlencoded
Cookie: .ASPXAUTH={authentication-token}
toAcct=67890&amount=250.00

Penyerang mengeksploitasi fakta bahwa pengguna mungkin masih memiliki token autentikasi yang valid untuk situs web target, dan dia menggunakan cuplikan kecil Javascript untuk menyebabkan browser membuat HTTP POST ke situs target secara otomatis. Jika token autentikasi masih valid, situs perbankan akan memulai transfer sebesar $250 ke dalam rekening yang dipilih penyerang.

Mitigasi yang tidak efektif

Sangat menarik untuk dicatat bahwa dalam skenario di atas, fakta bahwa WoodgroveBank.com diakses melalui SSL dan memiliki cookie autentikasi khusus SSL tidak cukup untuk menggagalkan serangan. Penyerang dapat menentukan skema URI (https) dalam elemen formulirnya<>, dan browser akan terus mengirim cookie yang tidak kedaluwarsa ke situs target selama cookie tersebut konsisten dengan skema URI dari target yang dimaksudkan.

Seseorang bisa berpendapat bahwa pengguna seharusnya tidak mengunjungi situs yang tidak tepercaya, karena hanya mengunjungi situs tepercaya yang membantu tetap aman online. Ada beberapa kebenaran untuk ini, tetapi sayangnya saran ini tidak selalu praktis. Mungkin pengguna "mempercayai" situs berita lokal ConsolidatedMessenger.com dan pergi mengunjungi situs itu sebagai gantinya, tetapi situs itu memiliki kerentanan XSS yang memungkinkan penyerang untuk menyuntikkan cuplikan kode yang sama yang berjalan di fabrikam.com.

Anda dapat memverifikasi bahwa permintaan masuk memiliki header Referen yang mereferensikan domain Anda. Ini akan menghentikan permintaan yang tanpa disadari dikirimkan dari domain pihak ketiga. Namun, beberapa orang menonaktifkan header Referen browser mereka karena alasan privasi, dan penyerang kadang-kadang dapat merusak header itu jika korban memiliki perangkat lunak tidak aman tertentu yang diinstal. Memverifikasi header Referen tidak dianggap sebagai pendekatan yang aman untuk mencegah serangan XSRF.

Mitigasi XSRF Runtime Web Stack

ASP.NET Web Stack Runtime menggunakan varian pola token penyinkron untuk bertahan dari serangan XSRF. Bentuk umum pola token penyinkron adalah bahwa dua token anti-XSRF dikirimkan ke server dengan setiap HTTP POST (Selain token autentikasi): satu token sebagai cookie, dan yang lainnya sebagai nilai formulir. Nilai token yang dihasilkan oleh runtime ASP.NET tidak deterministik atau dapat diprediksi oleh penyerang. Ketika token dikirimkan, server akan mengizinkan permintaan untuk melanjutkan hanya jika kedua token melewati pemeriksaan perbandingan.

Token sesi verifikasi permintaan XSRF disimpan sebagai cookie HTTP dan saat ini berisi informasi berikut dalam payloadnya:

  • Token keamanan, yang terdiri dari pengidentifikasi 128-bit acak.
    Gambar berikut menunjukkan token sesi verifikasi permintaan XSRF yang ditampilkan dengan alat pengembang Internet Explorer F12: (Perhatikan ini adalah implementasi saat ini dan subjek, bahkan kemungkinan, berubah.)

Cuplikan layar yang memperlihatkan halaman Indeks Aplikasi MY A S P dot NET M V C. Tab Jaringan terbuka.

Token bidang disimpan sebagai <input type="hidden" /> dan berisi informasi berikut dalam payload-nya:

Payload token anti-XSRF dienkripsi dan ditandatangani, sehingga Anda tidak dapat melihat nama pengguna saat menggunakan alat untuk memeriksa token. Ketika aplikasi web menargetkan ASP.NET 4.0, layanan kriptografi disediakan oleh rutinitas MachineKey.Encode . Ketika aplikasi web menargetkan ASP.NET 4.5 atau lebih tinggi, layanan kriptografi disediakan oleh rutinitas MachineKey.Protect , yang menawarkan performa, ekstensibilitas, dan keamanan yang lebih baik. Lihat posting blog berikut untuk detail selengkapnya:

Menghasilkan token

Untuk menghasilkan token anti-XSRF, panggil metode @Html.AntiForgeryToken dari tampilan MVC atau @AntiForgery.GetHtml() dari halaman Razor. Runtime kemudian akan melakukan langkah-langkah berikut:

  1. Jika permintaan HTTP saat ini sudah berisi token sesi anti-XSRF (cookie anti-XSRF __RequestVerificationToken), token keamanan diekstrak darinya. Jika permintaan HTTP tidak berisi token sesi anti-XSRF atau jika ekstraksi token keamanan gagal, token anti-XSRF acak baru akan dihasilkan.
  2. Token bidang anti-XSRF dihasilkan menggunakan token keamanan dari langkah (1) di atas dan identitas pengguna yang masuk saat ini. (Untuk informasi selengkapnya tentang menentukan identitas pengguna, lihat bagian Skenario dengan dukungan khusus di bawah ini.) Selain itu, jika IAntiForgeryAdditionalDataProvider dikonfigurasi, runtime akan memanggil metode GetAdditionalData dan menyertakan string yang dikembalikan dalam token bidang. (Lihat bagian Konfigurasi dan ekstensibilitas untuk informasi selengkapnya.)
  3. Jika token anti-XSRF baru dibuat pada langkah (1), token sesi baru akan dibuat untuk memuatnya dan akan ditambahkan ke koleksi cookie HTTP keluar. Token bidang dari langkah (2) akan dibungkus dalam <input type="hidden" /> elemen, dan markup HTML ini akan menjadi nilai pengembalian dari Html.AntiForgeryToken() atau AntiForgery.GetHtml().

Memvalidasi token

Untuk memvalidasi token anti-XSRF yang masuk, pengembang menyertakan atribut ValidateAntiForgeryToken pada tindakan atau pengontrol MVC-nya, atau dia memanggil @AntiForgery.Validate() dari halaman Razor-nya. Runtime akan melakukan langkah-langkah berikut:

  1. Token sesi masuk dan token bidang dibaca dan token anti-XSRF yang diekstrak dari masing-masing token. Token anti-XSRF harus identik per langkah (2) dalam rutinitas generasi.
  2. Jika pengguna saat ini diautentikasi, nama penggunanya dibandingkan dengan nama pengguna yang disimpan dalam token bidang. Nama pengguna harus cocok.
  3. Jika IAntiForgeryAdditionalDataProvider dikonfigurasi, runtime memanggil metode ValidateAdditionalData-nya . Metode harus mengembalikan nilai Boolean true.

Jika validasi berhasil, permintaan diizinkan untuk melanjutkan. Jika validasi gagal, kerangka kerja akan melempar HttpAntiForgeryException.

Kondisi kegagalan

Dimulai dengan ASP.NET Web Stack Runtime v2, HttpAntiForgeryException apa pun yang dilemparkan selama validasi akan berisi informasi terperinci tentang apa yang salah. Kondisi kegagalan yang saat ini ditentukan adalah:

  • Token sesi atau token formulir tidak ada dalam permintaan.
  • Token sesi atau token formulir tidak dapat dibaca. Penyebab paling mungkin dari ini adalah farm yang menjalankan versi The ASP.NET Web Stack Runtime yang tidak cocok atau farm tempat <elemen machineKey> di Web.config berbeda antar komputer. Anda dapat menggunakan alat seperti Fiddler untuk memaksa pengecualian ini dengan mengubah token anti-XSRF.
  • Token sesi dan token bidang ditukar.
  • Token sesi dan token bidang berisi token keamanan yang tidak cocok.
  • Nama pengguna yang disematkan dalam token bidang tidak cocok dengan nama pengguna yang masuk saat ini.
  • Metode IAntiForgeryAdditionalDataProvider.ValidateAdditionalData mengembalikan false.

Fasilitas anti-XSRF juga dapat melakukan pemeriksaan tambahan selama pembuatan atau validasi token, dan kegagalan selama pemeriksaan ini dapat mengakibatkan pengecualian dilemparkan. Lihat bagian autentikasi dan Konfigurasi berbasis klaim / ACS / WIFuntuk informasi selengkapnya.

Skenario dengan dukungan khusus

Autentikasi anonim

Sistem anti-XSRF berisi dukungan khusus untuk pengguna anonim, di mana "anonim" didefinisikan sebagai pengguna di mana properti IIdentity.IsAuthenticated mengembalikan false. Skenario termasuk memberikan perlindungan XSRF ke halaman login (sebelum pengguna diautentikasi) dan skema autentikasi kustom di mana aplikasi menggunakan mekanisme selain IIdentity untuk mengidentifikasi pengguna.

Untuk mendukung skenario ini, ingatlah bahwa token sesi dan bidang digabungkan dengan token keamanan, yang merupakan pengidentifikasi buram 128-bit yang dihasilkan secara acak. Token keamanan ini digunakan untuk melacak sesi pengguna individu saat ia menavigasi situs, sehingga secara efektif melayani tujuan pengidentifikasi anonim. String kosong digunakan sebagai pengganti nama pengguna untuk rutinitas pembuatan dan validasi yang dijelaskan di atas.

Autentikasi berbasis WIF / ACS / klaim

Biasanya, kelas IIdentity bawaan .NET Framework memiliki properti yang IIdentity.Name cukup untuk mengidentifikasi pengguna tertentu secara unik dalam aplikasi tertentu. Misalnya, FormsIdentity.Name mengembalikan nama pengguna yang disimpan dalam database keanggotaan (yang unik untuk semua aplikasi tergantung pada database tersebut), WindowsIdentity.Name mengembalikan identitas pengguna yang memenuhi syarat domain, dan sebagainya. Sistem ini tidak hanya menyediakan autentikasi; mereka juga mengidentifikasi pengguna ke aplikasi.

Di sisi lain, autentikasi berbasis klaim tidak selalu memerlukan identifikasi pengguna tertentu. Sebaliknya, jenis ClaimsPrincipal dan ClaimsIdentity dikaitkan dengan serangkaian instans Klaim , di mana klaim individu mungkin "berusia 18+ tahun" atau "adalah administrator" untuk hal lain. Karena pengguna belum tentu diidentifikasi, runtime tidak dapat menggunakan properti ClaimsIdentity.Name sebagai pengidentifikasi unik untuk pengguna tertentu ini. Tim telah melihat contoh dunia nyata di mana ClaimsIdentity.Name mengembalikan null, mengembalikan nama (tampilan) yang ramah, atau mengembalikan string yang tidak sesuai untuk digunakan sebagai pengidentifikasi unik untuk pengguna.

Banyak penyebaran yang menggunakan autentikasi berbasis klaim menggunakan Azure Access Control Service (ACS) khususnya. ACS memungkinkan pengembang untuk mengonfigurasi penyedia identitas individu (seperti ADFS, penyedia Akun Microsoft, penyedia OpenID seperti Yahoo!, dll.), dan penyedia identitas mengembalikan pengidentifikasi nama. Pengidentifikasi nama ini mungkin berisi Informasi Pengidentifikasi Pribadi (PII) seperti alamat email, atau dapat dianonimkan seperti Pengidentifikasi Pribadi Privat (PPID). Terlepas dari itu, tuple (penyedia identitas, pengidentifikasi nama) cukup berfungsi sebagai token pelacakan yang sesuai untuk pengguna tertentu saat dia menelusuri situs, sehingga ASP.NET Web Stack Runtime dapat menggunakan tuple sebagai pengganti nama pengguna saat menghasilkan dan memvalidasi token bidang anti-XSRF. URI tertentu untuk IdP dan pengidentifikasi nama adalah :

  • https://schemas.microsoft.com/accesscontrolservice/2010/07/claims/identityprovider
  • http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier

(lihat halaman dokumen ACS ini untuk informasi selengkapnya.)

Saat membuat atau memvalidasi token, ASP.NET Web Stack Runtime akan pada waktu proses mencoba mengikat ke jenis:

  • Microsoft.IdentityModel.Claims.IClaimsIdentity, Microsoft.IdentityModel, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35 (Untuk WIF SDK.)
  • System.Security.Claims.ClaimsIdentity (Untuk .NET 4.5).

Jika jenis ini ada, dan jika IIIIdentitas pengguna saat ini menerapkan atau subkelas salah satu jenis ini, fasilitas anti-XSRF akan menggunakan tuple (penyedia identitas, pengidentifikasi nama) sebagai pengganti nama pengguna saat membuat dan memvalidasi token. Jika tidak ada tuple seperti itu, permintaan akan gagal dengan kesalahan yang menjelaskan kepada pengembang cara mengonfigurasi sistem anti-XSRF untuk memahami mekanisme autentikasi berbasis klaim tertentu yang digunakan. Lihat bagian Konfigurasi dan ekstensibilitas untuk informasi selengkapnya.

Autentikasi OAuth / OpenID

Akhirnya, fasilitas anti-XSRF memiliki dukungan khusus untuk aplikasi yang menggunakan autentikasi OAuth atau OpenID. Dukungan ini berbasis heuristik: jika IIdentity.Name saat ini dimulai dengan http:// atau https://, maka perbandingan nama pengguna akan dilakukan menggunakan perbandingan Ordinal daripada perbandingan OrdinalIgnoreCase default.

Konfigurasi dan ekstensibilitas

Terkadang, pengembang mungkin menginginkan kontrol yang lebih ketat atas perilaku pembuatan dan validasi anti-XSRF. Misalnya, mungkin perilaku default pembantu MVC dan Halaman Web untuk secara otomatis menambahkan cookie HTTP ke respons tidak diinginkan, dan pengembang mungkin ingin mempertahankan token di tempat lain. Ada dua API untuk membantu hal ini:

AntiForgery.GetTokens(string oldCookieToken, out string newCookieToken, out string formToken);
AntiForgery.Validate(string cookieToken, string formToken);

Metode GetTokens mengambil sebagai input token sesi verifikasi permintaan XSRF yang ada (yang mungkin null) dan menghasilkan sebagai output token sesi verifikasi permintaan XSRF baru dan token bidang. Token hanyalah string buram tanpa dekorasi; nilai formToken misalnya tidak akan dibungkus dalam <tag input> . Nilai newCookieToken mungkin null; jika ini terjadi, maka nilai oldCookieToken masih valid dan tidak ada cookie respons baru yang perlu ditetapkan. Penelepon GetTokens bertanggung jawab untuk mempertahankan cookie respons yang diperlukan atau menghasilkan markup yang diperlukan; metode GetTokens itu sendiri tidak akan mengubah respons sebagai efek samping. Metode Validasi mengambil token sesi dan bidang yang masuk dan menjalankan logika validasi yang disebutkan di atasnya.

AntiForgeryConfig

Pengembang dapat mengonfigurasi sistem anti-XSRF dari Application_Start. Konfigurasi terprogram. Properti jenis AntiForgeryConfig statis dijelaskan di bawah ini. Sebagian besar pengguna yang menggunakan klaim akan ingin mengatur properti UniqueClaimTypeIdentifier.

Properti Deskripsi
AdditionalDataProvider IAntiForgeryAdditionalDataProvider yang menyediakan data tambahan selama pembuatan token dan menggunakan data tambahan selama validasi token. Nilai default-nya adalah null. Untuk informasi selengkapnya, lihat bagian IAntiForgeryAdditionalDataProvider .
CookieName String yang menyediakan nama cookie HTTP yang digunakan untuk menyimpan token sesi anti-XSRF. Jika nilai ini tidak diatur, nama akan dibuat secara otomatis berdasarkan jalur virtual yang disebarkan aplikasi. Nilai default-nya adalah null.
RequireSsl Boolean yang menentukan apakah token anti-XSRF diperlukan untuk dikirimkan melalui saluran yang diamankan SSL. Jika nilai ini benar, cookie yang dihasilkan secara otomatis akan memiliki bendera "aman" yang ditetapkan, dan API anti-XSRF akan melempar jika dipanggil dari dalam permintaan yang tidak dikirimkan melalui SSL. Nilai defaultnya adalah salah.
SuppressIdentityHeuristicChecks Boolean yang menentukan apakah sistem anti-XSRF harus menonaktifkan dukungannya untuk identitas berbasis klaim. Jika nilai ini benar, sistem akan mengasumsikan bahwa IIdentity.Name sesuai untuk digunakan sebagai pengidentifikasi per pengguna yang unik dan tidak akan mencoba IClaimsIdentity atau ClClaimsIdentity kasus khusus seperti yang dijelaskan di bagian autentikasi berbasis WIF / ACS / klaim . Nilai defaultnya adalah false.
UniqueClaimTypeidentifier String yang menunjukkan jenis klaim mana yang sesuai untuk digunakan sebagai pengidentifikasi per pengguna yang unik. Jika nilai ini ditetapkan dan IIdentity saat ini berbasis klaim, sistem akan mencoba mengekstrak klaim jenis yang ditentukan oleh UniqueClaimTypeIdentifier, dan nilai yang sesuai akan digunakan sebagai pengganti nama pengguna pengguna saat menghasilkan token bidang. Jika jenis klaim tidak ditemukan, sistem akan gagal dalam permintaan. Nilai default adalah null, yang menunjukkan bahwa sistem harus menggunakan tuple (penyedia identitas, pengidentifikasi nama) seperti yang dijelaskan sebelumnya sebagai pengganti nama pengguna pengguna.

IAntiForgeryAdditionalDataProvider

Jenis IAntiForgeryAdditionalDataProvider memungkinkan pengembang untuk memperluas perilaku sistem anti-XSRF dengan melakukan round-tripping data tambahan di setiap token. Metode GetAdditionalData dipanggil setiap kali token bidang dihasilkan, dan nilai yang dikembalikan disematkan dalam token yang dihasilkan. Pelaksana dapat mengembalikan tanda waktu, nonce, atau nilai lain yang dia inginkan dari metode ini.

Demikian pula, metode ValidateAdditionalData dipanggil setiap kali token bidang divalidasi, dan string "data tambahan" yang disematkan dalam token diteruskan ke metode . Rutinitas validasi dapat menerapkan batas waktu (dengan memeriksa waktu saat ini terhadap waktu yang disimpan saat token dibuat), rutinitas pemeriksaan nonce, atau logika lain yang diinginkan.

Keputusan desain dan pertimbangan keamanan

Token keamanan yang menautkan token sesi dan bidang secara teknis hanya diperlukan ketika mencoba melindungi pengguna anonim/ tidak diautentikasi terhadap serangan XSRF. Ketika pengguna diautentikasi, token autentikasi itu sendiri (mungkin dikirimkan dalam bentuk cookie) dapat digunakan sebagai setengah dari pasangan token penyinkron. Namun, ada skenario yang valid untuk melindungi halaman masuk yang dipukul oleh pengguna yang tidak diautentikasi, dan logika anti-XSRF dibuat lebih sederhana dengan selalu menghasilkan dan memvalidasi token keamanan, bahkan untuk pengguna yang diautentikasi. Ini juga memberikan beberapa perlindungan tambahan jika token lapangan pernah disusupi oleh penyerang, karena mengatur atau menebak token sesi akan menjadi rintangan lain bagi penyerang untuk mengatasinya.

Pengembang harus berhati-hati ketika beberapa aplikasi dihosting dalam satu domain. Misalnya, meskipun example1.cloudapp.net dan example2.cloudapp.net adalah host yang berbeda, ada hubungan kepercayaan implisit antara semua host di bawah domain *.cloudapp.net . 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). ASP.NET Web Stack Runtime menyediakan beberapa mitigasi di mana nama pengguna disematkan ke dalam token bidang, jadi bahkan jika subdomain berbahaya dapat menimpa token sesi, itu tidak akan dapat menghasilkan token bidang yang valid untuk pengguna. Namun, ketika dihosting di lingkungan seperti itu, rutinitas anti-XSRF bawaan masih tidak dapat bertahan terhadap pembajakan sesi atau login XSRF.

Rutinitas anti-XSRF saat ini tidak bertahan dari pembajakan klik. Aplikasi yang ingin mempertahankan diri dari pembajakan klik dapat dengan mudah melakukannya dengan mengirim X-Frame-Options: header SAMEORIGIN dengan setiap respons. Header ini didukung oleh semua browser terbaru. Untuk informasi selengkapnya, lihat blog IE, blog SDL, dan OWASP. ASP.NET Web Stack Runtime mungkin dalam beberapa rilis mendatang membuat pembantu MVC dan Halaman Web anti-XSRF secara otomatis mengatur header ini sehingga aplikasi secara otomatis terlindungi dari serangan ini.

Pengembang web harus terus memastikan bahwa situs mereka tidak rentan terhadap serangan XSS. Serangan XSS sangat kuat, dan eksploitasi yang sukses juga akan merusak pertahanan ASP.NET Web Stack Runtime terhadap serangan XSRF.

Pengakuan

@LeviBroderick, yang menulis banyak kode keamanan ASP.NET sebagian besar informasi ini.