-->

Should I use HTTP referrer validation or token ver

2020-07-06 03:12发布

问题:

I read about how to protect my web site from CSRF attacks in an ASP.NET MVC web application. They mentioned two ways to do so, either by:

  1. using Token Verification by using <@Html.AntiForgeryToken()> and [ValidateAntiforgeryToken]

  2. using HTTP referrer validation such as:

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

    and

    [IsPostedFromThisSite]
    public ActionResult Register(…)
    

So I got confused about whether I should use both of them to protect my web site from CSRF attacks or whether I can select one of these methods?

回答1:

Checking the referrer is problematic. First of all, the HTTP specification specifically allows for clients to not send referrer strings (for various privacy reasons). So, some of your clients may not include it. Second, referrer strings can be spoofed, where an attacker of sufficient skill can make them look like what they need to be in order to carry out a successful CSRF attack.

Using a CSRF validation token is a stronger approach and is the preferred method of mitigiation against CSRF attacks. You can read about why this is on the OWASP CSRF Cheat Sheet.

I will also point out that there is no reason why you cannot do both. A Defense-In-Depth (DiD) strategy is usually desirable, so that an attacker would need to defeat multiple, independent, defenses to execute a successful attack. You could implement a weak-referrer-checking approach (IF a referrer is provided by the client, make sure it is what it should be before acting on the request; if the referrer is not present, proceed as if it were present and correct) along with a CSRF validation token. That way, you check the referred information if the client provides it while still making use of the stronger validation token approach.



回答2:

As indicated by the other answers, using referrer checks on its own is not sufficient and you really should be using anti-forgery tokens.

However, as @jeffsix has pointed out, you can use referrer checks as a Defence-in-Depth (DID) strategy, so an attacker would need to defeat multiple, independent, defenses to execute a successful attack.

The ValidateReferrerAttribute attribute below can be used on your HttpPost MVC actions. If the referrer is null, it does nothing. If the referrer is not null then it checks that it is equal to the specified host name. You just need to add it wherever you are using the ValidateAntiForgeryTokenAttribute already, so it would be very easy to add.

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


回答3:

Although I've never used it, personally I'd avoid basing anything on HTTP_REFERER. I don't think it's commonplace now, but I remember a time where Internet security suites (e.g. Norton Internet Security) would block the HTTP_REFERER being sent. That's just going to mean genuine users can be prevented from using your site legitimately.

Edit: See this question.

I wouldn't count on it being reliable.



回答4:

The HTTP Referer (sic) header is not reliable. You should not depend on it for anything important. To quote Wikipedia's CSRF article:

"Checking the HTTP Referer header to see if the request is coming from an authorized page is commonly used for embedded network devices because it does not increase memory requirements. However a request that omits the Referer header must be treated as unauthorized because an attacker can suppress the Referer header by issuing requests from FTP or HTTPS URLs. This strict Referer validation may cause issues with browsers or proxies that omit the Referer header for privacy reasons. Also, old versions of Flash (before 9.0.18) allow malicious Flash to generate GET or POST requests with arbitrary HTTP request headers using CRLF Injection. Similar CRLF injection vulnerabilities in a client can be used to spoof the referrer of an HTTP request."

Referrer checking also won't help against persistent CSRF attacks, where the attacker manages to inject a malicious link directly onto your site. The only reliable way to protect against such attacks is to use anti-forgery tokens.