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?