Search code examples
angularsecuritycookiesjwtcsrf

Angular JWT in Cookie how to prevent CSRF/XSRF and XSS


I'm learning Angular and Express and I'm trying to implement a Login.

As I've understood it is better to store JWT in Cookies with "secure: true" and "httpOnly: true" as:

const jwtBearerToken = jwt.sign(...);

res.cookie("SESSIONID", jwtBearerToken, {httpOnly:true, secure:true});

in this way no JavaScrip can access the Cookie (since the "httpOnly: true"),

and I'm protected against XSS,

but also my SPA can't access the JWT this way and here come my question:

how can I be protected against CSRF/XSRF?

My Idea is this one:

  1. Put in the cookie a field named "cookie_id"

  2. Send also in the "res" Header the JWT that will contain the same field "cookie_id"

  3. store the JWT in LocalStorge

  4. Define an HttpInterceptor Mehtod that, for each "req" append the "cookie_id" in the HttpHeader

  5. Server Side check if the "cookie_id" in the cookie is the same as the "cookie_id" in the HttpHeader

it this the proper way to handel this?


Solution

  • First, note that just because an attacker cannot get your session cookie via injected javascript, you are not protected against xss. It's just the session cookie that cannot be stolen.

    The protection you described against csrf is called double submit, and it is an effective way to avoid csrf, if implemented correctly. Make sure the csrf token cookie is a different one (not the session cookie), and this is kind of an exception to the rule, you can leave the csrf cookie accessible to javascript (no need for httpOnly), because if there is xss, any csrf protection is useless anyway. Then upon requests from Angular, read that cookie, also send its value as a request header, and the server only has to compare as you described. The csrf token value needs to have enough entropy (ie. long and random enough) for it to be infeasible to be guessed. Also note that if you store it in localStorage instead of copying it to the request header directly from the cookie, that will be more error-prone. There is no need to use localStorage for this, the HttpInterceptor can copy directly from the csrf cookie too.