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 Jon Galloway
Tutorial ini menjelaskan bagaimana Anda dapat mencegah serangan pengalihan terbuka di aplikasi MVC ASP.NET Anda. Tutorial ini membahas perubahan yang telah dibuat di AccountController di ASP.NET MVC 3 dan menunjukkan bagaimana Anda dapat menerapkan perubahan ini dalam aplikasi MVC 1.0 dan 2 ASP.NET yang ada.
Apa itu Serangan Pengalihan Terbuka?
Aplikasi web apa pun yang mengalihkan ke URL yang ditentukan melalui permintaan seperti querystring atau data formulir berpotensi diubah untuk mengalihkan pengguna ke URL eksternal yang berbahaya. Perubahan ini disebut serangan pengalihan terbuka.
Setiap kali logika aplikasi Anda dialihkan ke URL tertentu, Anda harus memverifikasi bahwa URL pengalihan belum dirusak. Login yang digunakan dalam AccountController default untuk ASP.NET MVC 1.0 dan ASP.NET MVC 2 rentan terhadap serangan pengalihan terbuka. Untungnya, mudah untuk memperbarui aplikasi yang ada untuk menggunakan koreksi dari Pratinjau ASP.NET MVC 3.
Untuk memahami kerentanan, mari kita lihat cara kerja pengalihan masuk dalam proyek Aplikasi Web ASP.NET MVC 2 default. Dalam aplikasi ini, mencoba mengunjungi tindakan pengontrol yang memiliki atribut [Otorisasi] akan mengalihkan pengguna yang tidak sah ke tampilan /Account/LogOn. Pengalihan ke /Account/LogOn ini akan menyertakan parameter querystring returnUrl sehingga pengguna dapat dikembalikan ke URL yang awalnya diminta setelah mereka berhasil masuk.
Pada cuplikan layar di bawah ini, kita dapat melihat bahwa upaya untuk mengakses tampilan /Account/ChangePassword saat tidak masuk menghasilkan pengalihan ke /Account/LogOn? ReturnUrl=%2fAccount%2fChangePassword%2f.
Gambar 01: Halaman masuk dengan pengalihan terbuka
Karena parameter querystring ReturnUrl tidak divalidasi, penyerang dapat memodifikasinya untuk menyuntikkan alamat URL apa pun ke parameter untuk melakukan serangan pengalihan terbuka. Untuk menunjukkan hal ini, kita dapat memodifikasi parameter ReturnUrl menjadi https://bing.com, sehingga URL masuk yang dihasilkan adalah /Account/LogOn? ReturnUrl=https://www.bing.com/. Setelah berhasil masuk ke situs, kami dialihkan ke https://bing.com. Karena pengalihan ini tidak divalidasi, pengalihan ini dapat menunjuk ke situs berbahaya yang mencoba mengelabui pengguna.
Serangan Pengalihan Terbuka yang lebih kompleks
Serangan pengalihan terbuka sangat berbahaya karena penyerang tahu bahwa kami mencoba masuk ke situs web tertentu, yang membuat kita rentan terhadap serangan phishing. Misalnya, penyerang dapat mengirim email berbahaya ke pengguna situs web dalam upaya untuk mengambil kata sandi mereka. Mari kita lihat bagaimana ini akan bekerja di situs NerdDinner. (Perhatikan bahwa situs NerdDinner langsung telah diperbarui untuk melindungi dari serangan pengalihan terbuka.)
Pertama, penyerang mengirimi kami tautan ke halaman login di NerdDinner yang menyertakan pengalihan ke halaman yang dipalsukan:
http://nerddinner.com/Account/LogOn?returnUrl=http://nerddiner.com/Account/LogOn
Perhatikan bahwa URL kembali menunjuk ke nerddiner.com, yang kehilangan "n" dari kata makan malam. Dalam contoh ini, ini adalah domain yang dikontrol penyerang. Ketika kami mengakses tautan di atas, kami dibawa ke halaman login NerdDinner.com yang sah.
Gambar 02: Halaman masuk NerdDinner dengan pengalihan terbuka
Ketika kami masuk dengan benar, tindakan LogOn ASP.NET MVC AccountController mengalihkan kami ke URL yang ditentukan dalam parameter querystring returnUrl. Dalam hal ini, ini adalah URL yang telah dimasukkan penyerang, yaitu http://nerddiner.com/Account/LogOn
. Kecuali kami sangat waspada, kemungkinan besar kami tidak akan melihat ini, terutama karena penyerang telah berhati-hati untuk memastikan bahwa halaman yang dipalsukan terlihat persis seperti halaman masuk yang sah. Halaman masuk ini menyertakan pesan kesalahan yang meminta kami masuk lagi. Kami ceroroh, kami pasti salah mengetik kata sandi kami.
Gambar 03: Layar Masuk NerdDinner Yang Dipalsukan
Ketika kami mengetik ulang nama pengguna dan kata sandi kami, halaman login yang dipalsukan menyimpan informasi dan mengirim kami kembali ke situs NerdDinner.com yang sah. Pada titik ini, situs NerdDinner.com telah mengautentikasi kami, sehingga halaman masuk yang dipalsukan dapat dialihkan langsung ke halaman tersebut. Hasil akhirnya adalah bahwa penyerang memiliki nama pengguna dan kata sandi kami, dan kami tidak menyadari bahwa kami telah memberikannya kepada mereka.
Melihat kode yang rentan di Tindakan Masuk AccountController
Kode untuk tindakan Masuk dalam aplikasi ASP.NET MVC 2 ditunjukkan di bawah ini. Perhatikan bahwa setelah berhasil masuk, pengontrol mengembalikan pengalihan ke returnUrl. Anda dapat melihat bahwa tidak ada validasi yang dilakukan terhadap parameter returnUrl.
Mencantumkan tindakan Masuk 1 – ASP.NET MVC 2 di AccountController.cs
[HttpPost]
public ActionResult LogOn(LogOnModel model, string returnUrl)
{
if (ModelState.IsValid)
{
if (MembershipService.ValidateUser(model.UserName, model.Password))
{
FormsService.SignIn(model.UserName, model.RememberMe);
if (!String.IsNullOrEmpty(returnUrl))
{
return Redirect(returnUrl);
}
else
{
return RedirectToAction("Index", "Home");
}
}
else
{
ModelState.AddModelError("", "The user name or password provided is incorrect.");
}
}
// If we got this far, something failed, redisplay form
return View(model);
}
Sekarang mari kita lihat perubahan pada tindakan ASP.NET MVC 3 LogOn. Kode ini telah diubah untuk memvalidasi parameter returnUrl dengan memanggil metode baru di kelas pembantu System.Web.Mvc.Url bernama IsLocalUrl()
.
Mencantumkan 2 – ASP.NET tindakan Masuk MVC 3 di AccountController.cs
[HttpPost]
public ActionResult LogOn(LogOnModel model, string returnUrl)
{
if (ModelState.IsValid)
{
if (MembershipService.ValidateUser(model.UserName, model.Password))
{
FormsService.SignIn(model.UserName, model.RememberMe);
if (Url.IsLocalUrl(returnUrl))
{
return Redirect(returnUrl);
}
else
{
return RedirectToAction("Index", "Home");
}
}
else
{
ModelState.AddModelError("",
"The user name or password provided is incorrect.");
}
}
// If we got this far, something failed, redisplay form
return View(model);
}
Ini telah diubah untuk memvalidasi parameter URL pengembalian dengan memanggil metode baru di kelas pembantu System.Web.Mvc.Url, IsLocalUrl()
.
Melindungi Aplikasi MVC 1.0 dan MVC 2 ASP.NET Anda
Kita dapat memanfaatkan perubahan ASP.NET MVC 3 dalam aplikasi ASP.NET MVC 1.0 dan 2 yang ada dengan menambahkan metode pembantu IsLocalUrl() dan memperbarui tindakan LogOn untuk memvalidasi parameter returnUrl.
Metode UrlHelper IsLocalUrl() sebenarnya hanya memanggil metode di System.Web.WebPages, karena validasi ini juga digunakan oleh aplikasi ASP.NET Web Pages.
Daftar 3 – Metode IsLocalUrl() dari urlHelper ASP.NET MVC 3 class
public bool IsLocalUrl(string url) {
return System.Web.WebPages.RequestExtensions.IsUrlLocalToHost(
RequestContext.HttpContext.Request, url);
}
Metode IsUrlLocalToHost berisi logika validasi aktual, seperti yang ditunjukkan dalam Daftar 4.
Daftar 4 - Metode IsUrlLocalToHost() dari kelas System.Web.WebPages RequestExtensions
public static bool IsUrlLocalToHost(this HttpRequestBase request, string url)
{
return !url.IsEmpty() &&
((url[0] == '/' && (url.Length == 1 ||
(url[1] != '/' && url[1] != '\\'))) || // "/" or "/foo" but not "//" or "/\"
(url.Length > 1 &&
url[0] == '~' && url[1] == '/')); // "~/" or "~/foo"
}
Dalam aplikasi MVC 1.0 atau 2 ASP.NET kami, kami akan menambahkan metode IsLocalUrl() ke AccountController, tetapi Anda dianjurkan untuk menambahkannya ke kelas pembantu terpisah jika memungkinkan. Kami akan membuat dua perubahan kecil pada IsLocalUrl() versi MVC 3 ASP.NET sehingga akan berfungsi di dalam AccountController. Pertama, kita akan mengubahnya dari metode publik ke metode privat, karena metode publik dalam pengontrol dapat diakses sebagai tindakan pengontrol. Kedua, kita akan memodifikasi panggilan yang memeriksa host URL terhadap host aplikasi. Panggilan itu menggunakan bidang RequestContext lokal di kelas UrlHelper. Alih-alih menggunakan ini. RequestContext.HttpContext.Request.Url.Host, kami akan menggunakan ini. Request.Url.Host. Kode berikut menunjukkan metode IsLocalUrl() yang dimodifikasi untuk digunakan dengan kelas pengontrol di ASP.NET aplikasi MVC 1.0 dan 2.
Daftar 5 – Metode IsLocalUrl(), yang dimodifikasi untuk digunakan dengan kelas Pengontrol MVC
private bool IsLocalUrl(string url)
{
if (string.IsNullOrEmpty(url))
{
return false;
}
else
{
return ((url[0] == '/' && (url.Length == 1 ||
(url[1] != '/' && url[1] != '\\'))) || // "/" or "/foo" but not "//" or "/\"
(url.Length > 1 &&
url[0] == '~' && url[1] == '/')); // "~/" or "~/foo"
}
}
Sekarang setelah metode IsLocalUrl() diberlakukan, kita dapat memanggilnya dari tindakan LogOn kita untuk memvalidasi parameter returnUrl, seperti yang ditunjukkan dalam kode berikut.
Listing 6 – Metode LogOn yang diperbarui yang memvalidasi parameter returnUrl
[HttpPost]
public ActionResult LogOn(LogOnModel model, string returnUrl)
{
if (ModelState.IsValid)
{
if (MembershipService.ValidateUser(model.UserName, model.Password))
{
FormsService.SignIn(model.UserName, model.RememberMe);
if (IsLocalUrl(returnUrl))
{
return Redirect(returnUrl);
}
else
{
return RedirectToAction("Index", "Home");
}
}
else
{
ModelState.AddModelError("",
"The user name or password provided is incorrect.");
}
}
}
Sekarang kita dapat menguji serangan pengalihan terbuka dengan mencoba masuk menggunakan URL pengembalian eksternal. Mari kita gunakan /Account/LogOn? ReturnUrl=https://www.bing.com/ lagi.
Gambar 04: Menguji Tindakan Masuk yang diperbarui
Setelah berhasil masuk, kami diarahkan ke tindakan Home/Index Controller daripada URL eksternal.
Gambar 05: Serangan Pengalihan Terbuka dikalahkan
Ringkasan
Serangan pengalihan terbuka dapat terjadi ketika URL pengalihan diteruskan sebagai parameter dalam URL untuk aplikasi. Templat ASP.NET MVC 3 menyertakan kode untuk melindungi dari serangan pengalihan terbuka. Anda dapat menambahkan kode ini dengan beberapa modifikasi pada aplikasi MVC 1.0 dan 2 ASP.NET. Untuk melindungi dari serangan pengalihan terbuka saat masuk ke aplikasi ASP.NET 1.0 dan 2, tambahkan metode IsLocalUrl() dan validasi parameter returnUrl dalam tindakan LogOn.