Search code examples
asp.net-mvccsrfasp.net-mvc-5.2antiforgerytokencookie-path

How to set the AntiForgeryToken cookie path


The former HtmlHelper.AntiForgeryToken method which allows one to override the string path is deprecated.

[ObsoleteAttribute("This method is deprecated. Use the AntiForgeryToken() method instead. To specify a custom domain for the generated cookie, use the <httpCookies> configuration element. To specify custom data to be embedded within the token, use the static AntiForgeryConfig.AdditionalDataProvider property.", 
    true)]
public MvcHtmlString AntiForgeryToken(
    string salt,
    string domain,
    string path
)

Tells you to use <httpCookies>. BUT httpCookies Element does not have a setting for PATH.

Is this an oversight in the deprecation of this method? What is the best way to overwrite this cookie path? (manually?) Running website in a virtual application is not implicitly adding the application path to the __RequestVeririfcation cookie.


Solution

  • Looking at the deprecation message:

    "This method is deprecated. Use the AntiForgeryToken() method instead. To specify a custom domain for the generated cookie, use the configuration element. To specify custom data to be embedded within the token, use the static AntiForgeryConfig.AdditionalDataProvider property."

    It tells us we can validate additional parameters whenever the forgery token is read back. So even if we can't set the path in the cookie, we can set the path as a property inside the token. To validate it later on, for example:

    public class AdditionalDataProvider : IAntiForgeryAdditionalDataProvider
    {
        public string GetAdditionalData(HttpContextBase context)
        {
            return AdditionalData(context);
        }
    
        public bool ValidateAdditionalData(HttpContextBase context, string additionalData)
        {
            var currentData = AdditionalData(context);
            return currentData == additionalData;
        }
    
        private static string AdditionalData(HttpContextBase context)
        {
            var path = context.Request.ApplicationPath;
            return path;
        }
    }
    

    When asp.net generates the token it will store the current path (or any other unique value you want to validate) for that app and if you have another app running on a different path, when the token gets sent to that app (due to the lack of cookie path) it will validate the previous app properties against that app's properties. If it is a different set of properties it will fail and deny the request.

    Additionally, looking at the code for the AntiforgeryConfig.cs, if the app is running in a virtual directory, it will add that virtual directory in the cookie's name by default:

    private static string GetAntiForgeryCookieName()
    {
        return GetAntiForgeryCookieName(HttpRuntime.AppDomainAppVirtualPath);
    }
    
    // If the app path is provided, we're generating a cookie name rather than a field name, and the cookie names should
    // be unique so that a development server cookie and an IIS cookie - both running on localhost - don't stomp on
    // each other.
    internal static string GetAntiForgeryCookieName(string appPath)
    {
        if (String.IsNullOrEmpty(appPath) || appPath == "/")
        {
            return AntiForgeryTokenFieldName;
        }
        else
        {
            return AntiForgeryTokenFieldName + "_" + HttpServerUtility.UrlTokenEncode(Encoding.UTF8.GetBytes(appPath));
        }
    }
    

    So it will be like this: _RequestVerificationToken vs _RequestVerificationToken_L2RIdjAz0

    Meaning App2 although can receive tokens from App1, it won't be able to read them since it will be looking always for App2 verification token only.

    HTH