Entendiendo la falsificación de solicitudes entre sitios en .NET

Solo puede producir aplicaciones web seguras teniendo en cuenta la seguridad desde el principio. Esto requiere pensar en las posibles formas en que alguien podría atacar su sitio al crear cada página, forma y acción. También requiere comprender los tipos más comunes de problemas de seguridad y cómo abordarlos..

El tipo más común de agujero de seguridad en una página web le permite a un atacante ejecutar comandos en nombre de un usuario, pero desconocido para el usuario. El ataque de falsificación de solicitud entre sitios explota la confianza que un sitio web ya ha establecido con el navegador web de un usuario.

En este tutorial, analizaremos qué es un ataque de falsificación de solicitud entre sitios y cómo se ejecuta. Luego, construiremos una aplicación MVC de ASP.NET simple que sea vulnerable a este ataque y arreglaremos la aplicación para evitar que vuelva a suceder..


¿Qué es la falsificación de solicitud entre sitios??

El ataque de falsificación de solicitud entre sitios primero asume que la víctima ya se ha autenticado en un sitio web de destino, como un sitio bancario, Paypal u otro sitio para ser atacado. Esta autenticación debe almacenarse de forma tal que, si el usuario abandona el sitio y vuelve, el sitio web de destino todavía lo vea como iniciado. El atacante debe hacer que la víctima acceda a una página o enlace que ejecutará una solicitud o publicará en el sitio web de destino. Si el ataque funciona, entonces el sitio web de destino verá una solicitud proveniente de la víctima y la ejecutará como ese usuario. Esto, en efecto, le permite al atacante ejecutar cualquier acción deseada en el sitio web objetivo como víctima. El resultado potencial podría transferir dinero, restablecer una contraseña o cambiar una dirección de correo electrónico en el sitio web objetivo.

Cómo funciona el ataque

El acto de conseguir que la víctima use un enlace no requiere que haga clic en un enlace. Un simple enlace de imagen podría ser suficiente:

La inclusión de un enlace como este en una publicación de un foro, comentario de blog o sitio de redes sociales, por lo demás aparentemente inocuo, podría sorprender a un usuario. Los ejemplos más complejos utilizan JavaScript para crear una solicitud de publicación HTTP completa y enviarla al sitio web de destino.


Construyendo una aplicación web vulnerable en ASP.NET MVC

Vamos a crear una aplicación MVC de ASP.NET simple y dejarla vulnerable a este ataque. Usaré Visual Studio 2012 para estos ejemplos, pero esto también funcionará en Visual Studio 2010 o Visual Web Developer 2010 funcionará si ha instalado el soporte para MVC 4, que se puede descargar e instalar desde Microsoft.


Comience por crear un nuevo proyecto y elija utilizar el Proyecto de internet modelo. Cualquier motor de vista funcionará, pero aquí usaré el motor de vista ASPX.

Agregaremos un campo a la tabla UserProfile para almacenar una dirección de correo electrónico. Debajo Explorador de servidores expandir Conexiones de datos. Deberías ver el Conexión por defecto creado con la información para los inicios de sesión y membresías. Haga clic derecho en el Perfil del usuario tabla y haga clic Definición de tabla abierta. En la línea en blanco debajo de Nombre de usuario Tabla, agregaremos una nueva columna para el correo electrónico. Nombra la columna dirección de correo electrónico, dale el tipo nvarchar (MAX), y compruebe el Permitir nulos opción. Ahora haga clic Actualizar Guardar la nueva versión de la tabla..

Esto nos da una plantilla básica de una aplicación web, con soporte de inicio de sesión, muy similar a lo que muchos escritores comenzarían con tratar de crear una aplicación. Si ejecuta la aplicación ahora, verá que se muestra y es funcional. prensa F5 o usar DEBUG -> Iniciar la depuración Desde el menú para que aparezca el sitio web..


Vamos a crear una cuenta de prueba que podamos usar para este ejemplo. Haga clic en el Registro vincula y crea una cuenta con cualquier nombre de usuario y contraseña que desees. Aquí voy a usar una cuenta llamada testuser. Después de la creación, verás que ahora estoy conectado como usuario de prueba. Después de hacer esto, salga y agreguemos una página a esta aplicación para permitir al usuario cambiar su correo electrónico.


Antes de crear esa página para cambiar la dirección de correo electrónico, primero debemos hacer un cambio en la aplicación para que el código tenga conocimiento de la nueva columna que acabamos de agregar. Abre el AccountModels.cs archivo bajo el Modelos carpeta y actualizar el Perfil del usuario clase para que coincida con lo siguiente. Esto le dice a la clase sobre nuestra nueva columna donde almacenaremos la dirección de correo electrónico de la cuenta.

[Table ("UserProfile")] public class UserProfile [Key] [DatabaseGeneratedAttribute (DatabaseGeneratedOption.Identity)] public int UserId get; conjunto;  cadena pública Nombre de usuario obtener; conjunto;  public string EmailAddress get; conjunto; 

Abre el AccountController.cs expediente. Después de la RemoveExternalLogins Función agregar el siguiente código para crear una nueva acción. Esto obtendrá el correo electrónico actual para el usuario registrado y lo pasará a la vista para la acción.

public ActionResult ChangeEmail () // Obtenga el nombre de usuario registrado en la cadena username = WebSecurity.CurrentUserName; string currentEmail; utilizando (UsersContext db = new UsersContext ()) UserProfile user = db.UserProfiles.FirstOrDefault (u => u.UserName.ToLower () == nombre de usuario); currentEmail = user.EmailAddress;  volver vista (currentEmail); 

También necesitamos agregar la vista correspondiente para esta acción. Este debería ser un archivo llamado ChangeEmail.aspx bajo la Vistas \ Cuenta carpeta:

<%@ Page Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage"%>  Cambiar dirección de correo electrónico   

Cambiar dirección de correo electrónico

Dirección de email actual: <%= Model ?? "No hay correo electrónico actual"%>

<% using(Html.BeginForm()) %> <% %>

Esto nos da una nueva página que podemos usar para cambiar la dirección de correo electrónico del usuario que ha iniciado sesión actualmente.


Si corremos esta página y vamos a la / Cuenta / ChangeEmail Acción, ahora vemos que actualmente no tenemos un correo electrónico. Pero tenemos un cuadro de texto y un botón que podemos usar para corregirlo. Sin embargo, primero debemos crear la acción que se ejecutará cuando se envíe el formulario de esta página..

[HttpPost] public ActionResult ChangeEmail (ChangeEmailModel model) string username = WebSecurity.CurrentUserName; utilizando (UsersContext db = new UsersContext ()) UserProfile user = db.UserProfiles.FirstOrDefault (u => u.UserName.ToLower () == nombre de usuario); user.EmailAddress = model.NewEmail; db.SaveChanges ();  // Y para verificar el cambio, obtenga el correo electrónico del perfil ChangeEmailModel newModel = new ChangeEmailModel (); utilizando (UsersContext db = new UsersContext ()) UserProfile user = db.UserProfiles.FirstOrDefault (u => u.UserName.ToLower () == nombre de usuario); newModel.CurrentEmail = user.EmailAddress;  volver Ver (nuevoModelo); 

Después de hacer este cambio, ejecute el sitio web y de nuevo vaya a la / Cuenta / ChangeEmail Acción que acabamos de crear. Ahora puede ingresar una nueva dirección de correo electrónico y hacer clic en Cambiar e-mail botón y ver que la dirección de correo electrónico se actualizará.


Atacando el sitio

Como está escrito, nuestra aplicación es vulnerable a un ataque de falsificación de solicitud entre sitios. Añadamos una página web para ver este ataque en acción. Vamos a agregar una página dentro del sitio web que cambiará el correo electrónico a un valor diferente. En el HomeController.cs archivo agregaremos una nueva acción llamada AttackForm.

public ActionResult AttackForm () return View (); 

También añadiremos una vista para este nombre. AttackForm.aspx bajo la / Vistas / Inicio carpeta. Debe tener un aspecto como este:

<%@ Page Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage"%>  Formulario de ataque   

Formulario de ataque

Esta página tiene una forma oculta, para atacarte, cambiando tu correo electrónico:

Nuestra página anuncia útilmente sus malas intenciones, lo que, por supuesto, un verdadero ataque no haría. Esta página contiene un formulario oculto que no será visible para el usuario. Luego utiliza Javascript para enviar automáticamente este formulario cuando se carga la página..


Si ejecuta el sitio de nuevo y vaya a la / Inicio / AttackForm En la página, verás que se carga muy bien, pero sin una indicación externa de que algo haya sucedido. Si ahora vas a la / Cuenta / ChangeEmail Sin embargo, verás que tu correo electrónico ha sido cambiado a [email protected]. Aquí, por supuesto, intencionalmente lo estamos haciendo obvio, pero en un ataque real, es posible que no note que su correo electrónico ha sido modificado..


Mitigación de la falsificación de solicitudes entre sitios

Hay dos formas principales de mitigar este tipo de ataque. Primero, podemos verificar la referencia de la que proviene la solicitud web. Esto debe indicar a la aplicación cuando el envío de un formulario no proviene de nuestro servidor. Esto tiene dos problemas sin embargo. Muchos servidores proxy eliminan esta información de referencia, ya sea intencionalmente para proteger la privacidad o como efecto secundario, lo que significa que una solicitud legítima no puede contener esta información. También es posible que un atacante falsifique la referencia, aunque aumenta la complejidad del ataque..

El método más efectivo es exigir que exista un token específico del usuario para cada envío de formulario. El valor de este token se debe generar aleatoriamente cada vez que se crea el formulario y el formulario solo se acepta si se incluye el token. Si falta el token o se incluye un valor diferente, no permitimos el envío del formulario. Este valor se puede almacenar en el estado de sesión del usuario o en una cookie para permitirnos verificar el valor cuando se envía el formulario..

ASP.NET facilita este proceso, ya que el soporte de CSRF está integrado. Para usarlo, solo necesitamos realizar dos cambios en nuestro sitio web.


Arreglando el Problema

Primero, debemos agregar el token único al formulario para cambiar el correo electrónico del usuario cuando lo mostramos. Actualice el formulario en el ChangeEmail.aspx ver debajo / Cuenta / ChangeForm:

<% using(Html.BeginForm())  %> <%: Html.AntiForgeryToken() %> <%: Html.TextBoxFor(t=>t.NewEmail)%>  <%  %>

Esta nueva línea: <%: Html.AntiForgeryToken() %> le dice a ASP.NET que genere un token y lo coloque como un campo oculto en el formulario. Además, el marco se encarga de colocarlo en otra ubicación donde la aplicación pueda acceder a él más tarde para verificarlo..

Si cargamos la página ahora y miramos la fuente, veremos esta nueva línea, en el formulario, representada en el navegador. Este es nuestro token:

También debemos hacer un cambio en nuestra acción para hacerle saber que hemos agregado este token y que debe verificar el token antes de aceptar el formulario publicado..

De nuevo, esto es simple en ASP.NET MVC. En la parte superior de la acción que creamos para manejar el formulario publicado, el que tiene la [HttpPost] atributo agregado, agregaremos otro atributo llamado [ValidateAntiForgeryToken]. Esto hace que el inicio de nuestra acción se vea como lo siguiente:

 [HttpPost] [ValidateAntiForgeryToken] public ActionResult ChangeEmail (ChangeEmailModel model) string username = WebSecurity.CurrentUserName; * resto de funciones omitidas *

Vamos a probar esto. Primero ve al / Cuenta / ChangeEmail página y restaurar el correo electrónico de su cuenta a un valor conocido. Entonces podemos volver a la / Inicio / AttackForm Página y otra vez el código de ataque intenta cambiar nuestro correo electrónico. Si vuelves a la / Cuenta / ChangeEmail página de nuevo, esta vez verá que su correo electrónico ingresado anteriormente sigue siendo seguro e intacto. Los cambios que hicimos en nuestra forma y acción han protegido esta página del ataque..

Si tuviera que mirar el formulario de ataque directamente (fácilmente, quitando la