hansmaad
hansmaad

Reputation: 18905

Risk of using a persitent XSRF-TOKEN cookie in Angular

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

Answers (3)

SilverlightFox
SilverlightFox

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

Neil Smithline
Neil Smithline

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

Jossef Harush Kadouri
Jossef Harush Kadouri

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';
}]);

Test it

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

Related Questions