ASP.NET MVC - Anti-Forgery Token for all types of requests

Viewed 470

I am referencing the official Microsoft documentation for CSRF vulnerabilities: https://docs.microsoft.com/en-us/aspnet/web-api/overview/security/preventing-cross-site-request-forgery-csrf-attacks

I am adding protection to an ASP.NET MVC application where I CANNOT guarantee that GET requests do not have any side effects. The application is fairly large. I have decided to apply the solution discussed in the doc for ALL requests in the application. However, I am getting confused about how this works for requests where a form is not used to submit the request.

I have this login form:

<form action="~/Account/Login" method="post">
    @Html.AntiForgeryToken()
    <div id="loginView">
        <h3>Login</h3>
        <ul>
            <li><label for="UserName">User Name:</label> <input id="UserName" name="UserName" type="text" value="" /></li>
            <li><label for="Password">Password:</label>  <input type="password" id="Password" name="Password" value="" /></li>
            <li><input name="submit" type="submit" id="loginSubmit" value="Log In" /></li>
        </ul>
    </div>
</form>

There are several other @Html.AntiForgeryToken() throughout the application. Once the user logs in, requests are made in the background, by the user, etc.

Can the __RequestVerificationToken from the login form be used to verify all the other requests? The Microsoft documentation states to do this for Ajax requests:

<script>
@functions{
    public string TokenHeaderValue()
    {
        string cookieToken, formToken;
        AntiForgery.GetTokens(null, out cookieToken, out formToken);
        return cookieToken + ":" + formToken;                
    }
}

$.ajax("api/values", {
    type: "post",
    contentType: "application/json",
    data: {  }, // JSON data goes here
    dataType: "json",
    headers: {
        'RequestVerificationToken': '@TokenHeaderValue()'
    }
});
</script>

My understanding of this is that TokenHeaderValue() will be placed in some global file. Then, I'll have to add the token as a header for ALL requests.

Finally, I'll have to validate the token before each controller method is executed. I assume this is similar to this:

void ValidateRequestHeader(HttpRequestMessage request)
{
    string cookieToken = "";
    string formToken = "";

    IEnumerable<string> tokenHeaders;

    if (request.Headers.TryGetValues("RequestVerificationToken", out tokenHeaders))
    {
        string[] tokens = tokenHeaders.First().Split(':');

        if (tokens.Length == 2)
        {
            cookieToken = tokens[0].Trim();
            formToken = tokens[1].Trim();
        }
    }

    AntiForgery.Validate(cookieToken, formToken);
}

Am I missing anything? Is the approach correct?

0 Answers
Related