2012-02-14 7 views
9

Leí acerca de cómo proteger mi sitio web de los ataques CSRF en una aplicación web ASP.NET MVC. Se mencionan dos maneras de hacerlo, ya sea por:¿Debo usar la validación de referencias HTTP o la verificación de tokens para evitar los ataques de CSRF?

  1. utilizando clave de verificación mediante el uso de <@Html.AntiForgeryToken()> y [ValidateAntiforgeryToken]

  2. utilizando la validación referencia HTTP, tales como:

    public class IsPostedFromThisSiteAttribute : AuthorizeAttribute 
        { 
        public override void OnAuthorize(AuthorizationContext filterContext) 
         { 
         if (filterContext.HttpContext != null) 
          { 
          if (filterContext.HttpContext.Request.UrlReferrer == null) 
           throw new System.Web.HttpException("Invalid submission"); 
          if (filterContext.HttpContext.Request.UrlReferrer.Host != 
           "mysite.com") 
           throw new System.Web.HttpException 
            ("This form wasn't submitted from this site!"); 
          } 
         } 
        } 
    

    y

    [IsPostedFromThisSite] 
    public ActionResult Register(…) 
    

Entonces, ¿me confundí si debería usar ambos para proteger mi sitio web de los ataques CSRF o si puedo seleccionar uno de estos métodos?

Respuesta

10

Comprobar la referencia es problemático. En primer lugar, la especificación HTTP permite específicamente a los clientes no enviar cadenas de referencia (por diversas razones de privacidad). Por lo tanto, algunos de sus clientes pueden no incluirlo. En segundo lugar, las cadenas de referencia pueden ser falsificadas, donde un atacante con suficiente habilidad puede hacer que se vean como lo que necesitan para poder llevar a cabo un ataque de CSRF exitoso.

El uso de un token de validación CSRF es un enfoque más sólido y es el método preferido de mitigación contra los ataques CSRF. Puede leer acerca de por qué esto está en el OWASP CSRF Cheat Sheet.

También señalaré que no hay ninguna razón por la que no pueda hacer ambas cosas. Por lo general, es deseable una estrategia de Defensa en profundidad (DiD), de modo que un atacante tendría que vencer defensas múltiples e independientes para ejecutar un ataque exitoso. Podría implementar un enfoque de comprobación de referencia débil (si el cliente proporciona una referencia, asegúrese de que sea lo que debería ser antes de actuar en la solicitud; si la referencia no está presente, proceda como si estuviera presente y fuera correcta) junto con un token de validación CSRF. De esta forma, verifica la información referida si el cliente la proporciona al mismo tiempo que sigue utilizando el método de token de validación más sólido.

+1

+1: Un enfoque interesante. –

+1

pero es cierto que el enfoque de token antifalsificación eliminará la mayoría de los ataques basados ​​en CSRF, pero no detendrá los bots que buscan registrar automáticamente (y luego enviar correo basura) a los usuarios de su sitio. Entonces, ¿cómo puedo estar 100% seguro de que mi sitio web está protegido? –

+4

@johnG: Eso no es un ataque CSRF. Para detener spambots, lo que necesita es bueno [CAPTCHA] (http://en.wikipedia.org/wiki/CAPTCHA). (En realidad, [la seguridad a través de la oscuridad] (http://en.wikipedia.org/wiki/Security_through_obscurity) también puede funcionar bastante bien, al menos para sitios pequeños: si hace que su formulario de inicio de sesión sea lo suficientemente diferente de los demás, un nombre genérico bot no será capaz de entenderlo. Un spammer tendría que perder tiempo ajustando su bot solo para su sitio, lo que no es rentable para ellos a menos que su sitio sea realmente grande y popular.) –

2

El HTTP Referer (sic) encabezado is not reliable. No deberías depender de nada importante. Para citar Wikipedia's CSRF article:.

"Comprobación del HTTP Referer cabecera para ver si la solicitud proviene de una página autorizado se utiliza comúnmente para dispositivos de red integrado, ya que no aumenta los requisitos de memoria Sin embargo, una petición que omite la cabecera Referer debe tratarse como no autorizado porque un atacante puede suprimir el encabezado Referer emitiendo solicitudes de URL FTP o HTTPS. Esta estricta validación Referer puede causar problemas con los navegadores o los servidores que omiten el encabezado Referer por razones de privacidad. Además, las versiones anteriores de Flash (antes 9.0.18) permite que Flash malintencionado genere solicitudes GET o POST con encabezados de solicitud HTTP arbitrarios mediante inyección de CRLF. Inyección de CRLF similar. Las vulnerabilidades en un cliente se pueden usar para falsificar la referencia de una solicitud HTTP ".

La comprobación de referencias tampoco ayudará contra los ataques persistent CSRF, donde el atacante logra inyectar un enlace malicioso directamente en su sitio. La única manera confiable de protegerse contra tales ataques es usar tokens antifalsificación.

2

Aunque nunca lo he usado, personalmente evitaría basar nada en HTTP_REFERER. No creo que sea un lugar común ahora, pero recuerdo una época en la que las suites de seguridad de Internet (por ejemplo, Norton Internet Security) bloquearían el HTTP_REFERER que se envía. Eso solo significará que los usuarios genuinos pueden ser impedidos de usar su sitio legítimamente.

Editar: Ver this question.

No confiaría en que sea confiable.

1

Como lo indican las otras respuestas, el uso de controles de referencia por sí mismo no es suficiente y realmente debería usar tokens antifalsificación.

Sin embargo, como @jeffsix ha señalado, puede usar comprobaciones de referencia como una estrategia de defensa en profundidad (DID), por lo que un atacante tendría que derrotar múltiples defensas independientes para ejecutar un ataque exitoso.

El atributo ValidateReferrerAttribute a continuación se puede utilizar en sus acciones HttpPost MVC. Si el referente es nulo, no hace nada. Si el referente no es nulo, verifica que sea igual al nombre de host especificado. Solo tiene que agregarlo donde sea que esté utilizando ValidateAntiForgeryTokenAttribute, por lo que sería muy fácil de agregar.

/// <summary> 
/// For POST requests, checks that the requests referrer is the current site. This could be used along side the ValidateAntiForgeryToken 
/// Note that many clients do not send the referrer, so we do nothing in this case. 
/// This attribute can be used as part of a Defence-in-Depth (DID) strategy, so an 
/// attacker would need to defeat multiple, independent, defenses to execute a successful attack. 
/// </summary> 
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, Inherited = true, AllowMultiple = false)] 
public class ValidateReferrerAttribute : FilterAttribute, IAuthorizationFilter 
{ 
    /// <summary> 
    /// Called when authorization is required. 
    /// </summary> 
    /// <param name="filterContext">The filter context.</param> 
    /// <exception cref="System.ArgumentNullException">filterContext</exception> 
    public void OnAuthorization(AuthorizationContext filterContext) 
    { 
     if (filterContext == null) 
     { 
      throw new ArgumentNullException("filterContext"); 
     } 

     if ((filterContext.HttpContext.Request.UrlReferrer != null) && 
      string.Equals(filterContext.HttpContext.Request.HttpMethod, "POST", StringComparison.OrdinalIgnoreCase) && 
      !string.Equals(filterContext.HttpContext.Request.UrlReferrer.Host, filterContext.HttpContext.Request.Url.Host, StringComparison.OrdinalIgnoreCase)) 
     { 
      this.HandleExternalPostRequest(filterContext); 
     } 
    } 

    /// <summary> 
    /// Handles post requests that are made from an external source. 
    /// By default a 403 Forbidden response is returned. 
    /// </summary> 
    /// <param name="filterContext">The filter context.</param> 
    /// <exception cref="System.Web.HttpException">Request not allowed.</exception> 
    protected virtual void HandleExternalPostRequest(AuthorizationContext filterContext) 
    { 
     throw new HttpException((int)HttpStatusCode.Forbidden, "Request not allowed."); 
    } 
} 
+1

Solo para mejorar un poco tu código (y para facilitar su reutilización) puedes leer el host actual de 'filterContext.HttpContext.Request.Url.Host', lo que significa que no necesitas tener' '[HOST_NAME_HERE ] "' bit –

+0

Gracias @MatthewSteeples. Actualizado. –

Cuestiones relacionadas