【问题标题】:Should I use HTTP referrer validation or token verification to prevent CSRF attacks?我应该使用 HTTP 引用验证还是令牌验证来防止 CSRF 攻击?
【发布时间】:2012-03-06 05:15:11
【问题描述】:

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

  1. 通过<@Html.AntiForgeryToken()>[ValidateAntiforgeryToken] 使用令牌验证

  2. 使用 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(…)
    

所以我很困惑是否应该同时使用这两种方法来保护我的网站免受 CSRF 攻击,或者我是否可以选择其中一种方法?

【问题讨论】:

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


    【解决方案1】:

    如其他答案所示,仅使用引荐来源网址检查是不够的,您确实应该使用防伪令牌。

    但是,正如 @jeffsix 所指出的,您可以将引荐来源网址检查用作纵深防御 (DID) 策略,因此攻击者需要击败多个独立的防御措施才能成功执行攻击。

    下面的 ValidateReferrerAttribute 属性可用于您的 HttpPost MVC 操作。如果引用者为空,则不执行任何操作。如果引用者不为空,则检查它是否等于指定的主机名。您只需要在已经使用 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.");
        }
    }
    

    【讨论】:

    • 只是为了稍微改进您的代码(并使其更易于重用),您可以从filterContext.HttpContext.Request.Url.Host 读取当前主机,这意味着您不需要"[HOST_NAME_HERE]"
    • 谢谢@MatthewSteeples。已更新。
    【解决方案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 注入生成带有任意 HTTP 请求标头的 GET 或 POST 请求。客户端中的类似 CRLF 注入漏洞可用于欺骗 HTTP 请求的引用者。"

    Referrer 检查也无助于防止persistent CSRF 攻击,在这种攻击中,攻击者设法将恶意链接直接注入您的网站。防止此类攻击的唯一可靠方法是使用防伪令牌。

    【讨论】:

      【解决方案3】:

      检查引荐来源网址是有问题的。首先,HTTP 规范特别允许客户端不发送引用字符串(出于各种隐私原因)。因此,您的一些客户可能不包括它。其次,引用字符串可以被欺骗,有足够技能的攻击者可以使它们看起来像他们需要的那样,以便成功进行 CSRF 攻击。

      使用 CSRF 验证令牌是一种更强大的方法,并且是缓解 CSRF 攻击的首选方法。您可以在OWASP CSRF Cheat Sheet 上了解为什么会这样。

      我还要指出,你没有理由不能同时做这两件事。纵深防御 (DiD) 策略通常是可取的,因此攻击者需要击败多个独立的防御来执行成功的攻击。您可以实施弱引荐来源网址检查方法(如果客户端提供引荐来源网址,请确保在对请求采取行动之前它应该是什么;如果引荐来源网址不存在,就好像它存在并且正确一样继续进行)连同一个 CSRF 验证令牌。这样,如果客户端提供了引用的信息,您就可以检查它,同时仍然使用更强大的验证令牌方法。

      【讨论】:

      • 但是防伪造令牌方法确实可以消除大多数基于 CSRF 的攻击,但它不会阻止那些寻求自动注册(然后是垃圾邮件)用户到您的地点。所以我怎么能 100% 确定我的网站受到保护。
      • @johnG:这不是 CSRF 攻击。要阻止垃圾邮件程序,您需要的是 CAPTCHA。 (实际上,security through obscurity 也可以很好地工作,至少对于小型网站而言:如果您的登录表单与其他人的登录表单足够不同,那么通用机器人将无法理解它。垃圾邮件发送者将不得不花时间只为您的网站调整他们的机器人,这对他们来说并不划算,除非您的网站真的很大而且很受欢迎。)
      • @jeffsix 我喜欢包括“弱”引用检查的想法。这是一个不错的额外层。
      【解决方案4】:

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

      编辑:见this question

      我不指望它是可靠的。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-09-28
        • 2016-01-06
        • 2017-09-05
        • 1970-01-01
        • 1970-01-01
        • 2014-01-02
        • 2012-03-06
        • 2016-01-08
        相关资源
        最近更新 更多