Normally, when a site requires that you are logged in before you can access a certain page, you are taken to the login screen and after successfully authenticating yourself, you are redirected back to the originally requested page. This is great for usability - but without careful scrutiny, this feature can easily become an open redirect vulnerability.
Sadly, for an example of this vulnerability, look no further than the default LogOn action provided by ASP.NET MVC 2:
[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); // open redirect vulnerability HERE
} else {
return RedirectToAction("Index", "Home");
}
} else {
ModelState.AddModelError("", "User name or password incorrect...");
}
}
return View(model);
}
If a user is successfully authenticated, they are redirected to "returnUrl" (if it was provided via the login form submission).
Here is a simple example attack (one of many, actually) that exploits this vulnerability:
Attacker, pretending to be victim's bank, sends an email to victim containing a link, like this: http://www.mybank.com/logon?returnUrl=http://www.badsite.com
Having been taught to verify the ENTIRE domain name (e.g., google.com = GOOD, google.com.as31x.example.com = BAD), the victim knows the link is OK - there isn't any tricky sub-domain phishing going on.
The victim clicks the link, sees their actual familiar banking website and is asked to logon
Victim logs on and is subsequently redirected to http://www.badsite.com which is made to look exactly like victim's bank's website, so victim doesn't know he is now on a different site.
http://www.badsite.com says something like "We need to update our records - please type in some extremely personal information below: [ssn], [address], [phone number], etc."
Victim, still thinking he is on his banking website, falls for the ploy and provides attacker with the information
Any ideas on how to maintain this redirect-on-successful-login functionality yet avoid the open-redirect vulnerability?
I'm leaning toward the option of splitting the "returnUrl" parameter into controller/action parts and use "RedirectToRouteResult" instead of simply "Redirect". Does this approach open any new vulnerabilities?
Side note: I know this open-redirect may not seem to be a big deal compared to the likes of XSS and CSRF, but us developers are the only thing protecting our customers from the bad guys - anything we can do to make the bad guys' job harder is a win in my book.
Thanks, Brad