Reputation: 18905
This is related to this question CSRF Protection for Refresh Token Cookie in SPA
I want to use the recommended XSRF-TOKEN
cookie mechanism to protect another HttpOnly cookie. For this scenario I need to make the XSRF-TOKEN
cookie persitent, because it has to be available at app start up after a reload. The default implementation in Angular $http
looks up in session cookies only.
What are risks if I make the cookie persitent and manually set the X-XSRF-TOKEN
HTTP header?
Upvotes: 1
Views: 1417
Reputation: 33538
What are risks if I make the cookie persistent and manually set the X-XSRF-TOKEN HTTP header?
The risk is that an attacker could eventually brute force the token value.
The recommendation is to have a new CSRF token per session. If you make this persistent then a malicious site could keep trying to submit a cross site request including a different token value each time. Eventually it will try every combination of token character and succeed in making the request.
Practically however, the user would have to visit the malicious website at the same time and every time. This can happen with browsers that remember the user's open tabs and automatically load each time.
You could also build in some brute force protection. For example, after 10 requests made with an invalid CSRF token you could abort the session and then inform the user that they have been logged out. This will mitigate the brute force attack, however this converts the attack into a Denial of Service attack as the malicious website will be successful at logging out the user. Therefore you should follow this up by contacting the user and informing them that a site that they are visiting is attempting to compromise them (you can check your server logs to determine the referer
and origin
headers).
Upvotes: 3
Reputation: 1586
A CSRF attack works on an unprotected site to which the user is logged in. Consider site S that uses session cookie C (and nothing else) to identify a user's session. This means that the browser will send C on every request to S. As the presence of the session cookie is all that's required to confirm a session, the user will be logged in when they access S. This is great. Exactly what we want.
Except...
Let's assume that S can is a website that can email cash via an URL such as https://S/email-cash?email=recipient@examplecom
. An evil website E can have embed the link https://S/email-cash?email=ATTACKER@examplecom
in one of its pages. Now, when the user is browsing site E while logged into site S and they click on this link, they'll end up emailing the attacker money. Even worse, this link can be executed in JavaScript behind the scenes so the user only needs to visit site E. Very bad.
The problem happens because every request accompanied by a valid session ID cookie C is treated as a valid request. The solution is to require the browser to send some piece of ID that it could only have gotten very recently from site S. This is the CSRF token. There's no way for the browser to get it unless it is given it by S and S will only give it when it's serving a page, not for a cross-site attack.
Now if you start storing the CSRF token as a persistent cookie, it defeats the entire purpose because it becomes something that the browser can send on a cross-site attack.
Upvotes: 0
Reputation: 34207
If you choose to use Persistent cookies, you will be still vulnerable for CSRF attacks since the browser will send these cookies with the requests
For angularjs, the following is what i'm using in my SPA app; a CSRF token is generated by the backend server and passed as a header only in the request for the index.html
file. from that point angular is configured to add the token in the header + in a session cookie - for each internal $http.post/delete/put/...
requests
app.config(['$httpProvider', function ($httpProvider)
{
$httpProvider.defaults.xsrfCookieName = 'csrftoken';
$httpProvider.defaults.xsrfHeaderName = 'X-CSRFToken';
}]);
use this small snippet to manually test your api:
<!DOCTYPE html>
<html>
<head>
<script>
function csrf(id)
{
document.getElementById("csrf-form-" + id).submit();
}
</script>
</head>
<body>
<form method="POST" action="http://127.0.0.1:8080/api/test" enctype="text/plain" target="_blank" id="csrf-form-1">
<input name='{"protected":false, "ignore_me":"' value='test"}'type='hidden'>
</form>
<button onclick="csrf(1)"}>CSRF!</button>
</body>
</html>
Upvotes: 0