Normalmente, cuando un sitio requiere que haya iniciado sesión antes de poder acceder a una página determinada, está llevado a la pantalla de inicio de sesión y después de autenticarse con éxito, se le redirige a la página solicitada originalmente. Esto es ideal para la usabilidad, pero sin un escrutinio cuidadoso, esta característica puede convertirse fácilmente en una vulnerabilidad open redirect.Cómo evitar la vulnerabilidad de redireccionamiento abierto y redirigir de forma segura al inicio de sesión exitoso (SUGERENCIA: el código predeterminado de ASP.NET MVC 2 es vulnerable)
Lamentablemente, para un ejemplo de esta vulnerabilidad, no busque más que la acción de conexión predeterminada proporcionada por 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);
}
Si un usuario se autentica correctamente, se les redirige a "ReturnURL" (si fue proporcionado a través del formulario de ingreso).
Aquí es un simple ataque de ejemplo (uno de muchos, en realidad) que explota esta vulnerabilidad:
- El atacante, que pretende ser el banco de la víctima, envía un correo electrónico a la víctima que contiene un enlace, así:
http://www.mybank.com/logon?returnUrl=http://www.badsite.com
- Habiendo aprendido a verificar el nombre de dominio ENTERO (por ej., Google.com = BUENO, google.com.as31x.example.com = MALO), la víctima sabe que el enlace está bien - no hay ningún subdominio complicado phishing pasando.
- La víctima hace clic en el enlace, ve su sitio web real de banca familiar y se le pide que iniciar sesión
- Víctima inicia la sesión y, posteriormente, se redirige a
http://www.badsite.com
que se hace para parecerse exactamente a la página web del banco de la víctima, por lo que la víctima no lo hace sabe que ahora está en un sitio diferente. http://www.badsite.com
dice algo así como "Tenemos que actualizar nuestros registros: ingrese alguna información extremadamente personal a continuación: [ssn], [dirección], [número de teléfono], etc."- La víctima, aún pensando que es en su sitio web de banca, cae en la trampa y proporciona atacante con la información
Cualquier ideas sobre cómo mantener esta redirección-on-éxito-login funcionalidad sin embargo, evitar el abierto redirigir la vulnerabilidad?
Me inclino por la opción de dividir el parámetro "returnUrl" en partes de controlador/acción y usar "RedirectToRouteResult" en lugar de simplemente "Redirigir". ¿Este enfoque abre nuevas vulnerabilidades?
actualización
Por limitándome al controlador rutas/acción, no se puede redirigir a rutas personalizadas (por ejemplo /backend/calendar/2010/05/21
). Sé que al pasar más parámetros a la acción LogOn, I podría hacer que funcione, pero siento que siempre volveré a visitar este método, manteniéndolo actualizado con nuestro esquema de enrutamiento. Entonces, en lugar de dividir returnUrl en sus partes de controlador/acción, mantengo returnUrl tal como está y lo analizo para asegurarme de que contiene solo una ruta relativa (por ejemplo, /users/1
) y no una ruta absoluta (por ejemplo, http://www.badsite.com/users/1
).Aquí está el código que estoy usando:
private static bool CheckRedirect(string url) {
try {
new Uri(url, UriKind.Relative);
}
catch (UriFormatException e) {
return false;
}
return true;
}
Nota al margen: Sé que esto re-direccionamiento abierto puede no parecer una gran cosa en comparación con los gustos de XSS y CSRF, pero nosotros los desarrolladores son la única cosa proteger a nuestros clientes de los malos: cualquier cosa que podamos hacer para dificultar el trabajo de los malos es una victoria en mi libro.
Gracias, Brad
Si falla la memoria, ReturnURL debe coincidir con uno de sus rutas, o la cosa se YSOD. Pero podría estar equivocado. ¿Has probado esto para demostrar que es una vulnerabilidad? –
Acabo de probarlo. Es verdad. Otra pregunta relacionada [aquí] (http://stackoverflow.com/questions/2782710/what-is-it-about-the-default-asp-net-mvc-accountcontroller-code-that-some-hate) –
Si te hará sentir mejor, estoy bastante seguro de que el 'Redirect' no * hace * un POST, sino un GET solamente. Pero supongo que eso no te ayuda si la información confidencial también se transmite en la URL de redireccionamiento como parámetros. –