我应该使用HTTP引用者验证或令牌验证来防止CSRF攻击吗?

时间:2012-02-14 20:21:59

标签: asp.net-mvc-3 security csrf

我读过如何在ASP.NET MVC Web应用程序中保护我的网站免受CSRF攻击。他们提到了两种方法:

  1. 使用<@Html.AntiForgeryToken()>[ValidateAntiforgeryToken]

  2. 进行令牌验证
  3. 使用HTTP引荐来源验证,例如:

    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!");
                }
            }
        }
    

    [IsPostedFromThisSite]
    public ActionResult Register(…)
    
  4. 所以我很困惑我是否应该使用它们来保护我的网站免受CSRF攻击,或者我是否可以选择其中一种方法?

4 个答案:

答案 0 :(得分:10)

检查引荐来源是有问题的。首先,HTTP规范明确允许客户端不发送引用字符串(出于各种隐私原因)。因此,您的一些客户可能不会包含它。其次,引用者字符串可以被欺骗,具有足够技能的攻击者可以使它们看起来像是为了成功进行CSRF攻击。

使用CSRF验证令牌是一种更强大的方法,是抵御CSRF攻击的首选方法。您可以在OWASP CSRF Cheat Sheet上了解原因。

我还要指出,你没有理由不能同时做到这两点。通常需要防御深度(DiD)策略,以便攻击者需要击败多个独立的防御来执行成功的攻击。您可以实现弱引用者检查方法(如果客户提供引用者,请确保它在执行请求之前应该是什么;如果引用者不存在,则继续进行,就像它存在并且正确一样)以及CSRF验证令牌。这样,如果客户端提供它,同时仍然使用更强的验证令牌方法,则检查引用的信息。

答案 1 :(得分:2)

HTTP Referer(原文如此)标头is not reliable。你不应该依赖它来做任何重要的事情。引用Wikipedia's CSRF article

  

“检查HTTP Referer标头以查看请求是否来自授权页面通常用于嵌入式网络设备,因为它不会增加内存要求。但是请求省略Referer标头必须被视为未经授权,因为攻击者可以通过发出来自FTP或HTTPS URL的请求来抑制Referer标头。这种严格的Referer验证可能会导致浏览器或代理忽略Referer的问题标题出于隐私原因。此外,旧版本的Flash(9.0.18之前)允许恶意Flash使用CRLF Injection生成带有任意HTTP请求标头的GET或POST请求。客户端中的类似CRLF注入漏洞可用于欺骗引用者一个HTTP请求。“

引荐来源检查也无法帮助抵御persistent CSRF攻击,攻击者可以将恶意链接直接注入您的网站。防止此类攻击的唯一可靠方法是使用防伪标记。

答案 2 :(得分:2)

虽然我从未使用它,但我个人不会在HTTP_REFERER上做任何事情。我认为现在这种情况并不常见,但我记得互联网安全套件(例如Norton Internet Security)会阻止发送的HTTP_REFERER。这只是意味着可以阻止真正的用户合法使用您的网站。

修改:请参阅this question

我不指望它是可靠的。

答案 3 :(得分:2)

正如其他答案所示,单独使用引荐来源检查是不够的,你真的应该使用防伪令牌。

但是,正如@jeffsix指出的那样,您可以使用引荐来源检查作为深度防御(DID)策略,因此攻击者需要击败多个独立的防御来执行成功的攻击。<​​/ p >

下面的ValidateReferrerAttribute属性可用于您的HttpPost MVC操作。如果引用者为空,则不执行任何操作。如果引用者不为null,则它检查它是否等于指定的主机名。你只需要在任何使用ValidateAntiForgeryTokenAttribute的地方添加它,这样就可以很容易地添加。

/// <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.");
    }
}