Security Concerns: JWT + cookies for SPA - cookies

I'm reading about JWT, refresh tokens sessionIds and how to build a secure authentication with a SPA. From what I understood (assuming everything is HTTPS),
Using only JWT (or refreshToken for that matter), stored in localStorage/sessionStorage: Vulnerable to XSS attacks.
Using only sessionIDs (stateful server), stored in HTTPonly cookie: Vulnerable to CSRF attacks.
Using JWT (stateless server) stored in HTTPonly cookie: Vulnerable to CSRF.
So my idea: Why not store short-lived JWTs in localStorage and sessionIDs in HTTPonly cookies? Are there any security issues with this scheme? I can't find a lot of info on the net of this practice, why is that?
Thanks.

Related

How does a xsrf token cookie protect against csrf?

Wouldn't a malicious site be able to read the cookie using xss cookie stealing and put it in the header of an ajax request?
Of course, if the site is vulnerable to xss, it's also vulnerable to csrf, but that's the smaller issue then.
If there is no xss though, the attacker has no way to read the token due to the same origin policy.

Django SimpleJWT: Some questions with token authentication

I am implementing authentication in Django using SimpleJWT, and have a few questions regarding the same. To give some background I have multiple domains with my backend, some with normal login (username and password), and some with SSO logins.
Question 2:
Suppose, I store the access tokens in local storage and send the access token to all APIs, and I'm also refreshing it before it expires. But what will happen if the user closes the browser, and we are not able to refresh the access token. The access token expires and the user gets logged out. How can we keep the user logged in for a certain amount of time (say 30 days)?
When the Access token expires, you use the Refresh token to obtain a new Access token.
This works because Refresh token has a long life, typically up to 30 days (but can be even longer if you want).
Example:
User closes browser
Comes back 10 days later
User sends a request to the server
Server will return 401 Unauthorized response because Access token has expired
Your app will send a request to obtain a new Access token using the Refresh token
If the Refresh token is valid, server will return a new Access token
If the Refresh token is expired, server will return a 401 response. That means user needs to login again.
Security considerations
Personally, I think JWT for most web apps is not an suitable idea because of conflicting opinions and advice on how to securely store the tokens.
Since a Refresh token is really powerful, it is not advised to store it in the browser. So where do you store it? And that's when this misleading idea of "backendless" web services powered by JWT starts to fall apart.
Paradoxes regarding storing tokens:
Store it in localstorage: Vulnerable to XSS attacks.
This is really serious because the XSS vulnerabilities can also come from third party JS libraries, not just from your own code. Hackers can hijack a third-party library on NPM to inject malicious code and you might be unknowingly using it in your project (it might be a dependency of a dependency of another dependency...).
Store it in httponly cookies: Safe from XSS attacks but requires a first-party backend server (because third-party auth servers can't set cookies for another domain).
If you stop to think about it, you'll notice that this case is exactly similar to the regular session auth where a session token is saved in the cookie. So why not just use session auth instead of this complicated JWT setup?
I'm going to advise you to thoroughly research this and decide whether you really need JWT for your web apps.
JWT auth using cross-origin cookies
Since you mention that your frontend apps connect to an API server in another domain, using JWT seems alright.
If you control the API server, you can setup CORS headers to allow the API server to set cookies on your apps' domains.
Important:
Since this involves Cookies, it is vulnerable to CSRF attacks. But > that is easier to prevent using CSRF tokens.
That means, with every POST request, you'll need to send CSRF token
and the API server must also validate that CSRF token
Here's a diagram I make of the auth flow in that case:
For Question 2, add this code on your settings.py file
SIMPLE_JWT = {
'ACCESS_TOKEN_LIFETIME': timedelta(days=30),
'REFRESH_TOKEN_LIFETIME': timedelta(days=30),
}

HttpOnly Cookies with AWS Cognito

I am using the amazon-cognito-identity-js SDK for user authentication. The CookieStorage object only takes domain, path, expires, and secure configurations. Is it possible to configure the authentication response to set the tokens in an HttpOnly cookie?
See Set a cookie to HttpOnly via Javascript. It is not possible for JavaScript to set httpOnly cookies, so amazon-cognito-identity-js can't do that either.
If you use the hosted sign-in/up pages, then Cognito will put httpOnly cookies on your client (server side). But those cookies don't contain JWT's.
Found this, from the discussion it looks like httpOnly cookies are not something AWS Cognito currently supports (which is really surprising)
https://github.com/aws-amplify/amplify-js/issues/3224
Note: the discussion is around AWS amplify but httpOnly cookies can only be set by the server for the client, so it shouldn't matter what client library is being used.
You can set HttpOnly cookie via express js or any other server.
I created a wrapper, an "identity service" sor of for AWS Cognito, that returns HttpOnly Cookies, it is easily achieveable since cognito comes with jwt authentication out of the box.
Note that the project was originally created to support, nuxt/next js in case you want other structure just change the endpoints.
https://github.com/cnikolov/aws-cognito-http

Using JWT stored in HTTPonly & secure cookie: Vulnerable to CSRF. but not to XSS?

I understood webstorage is vulnerable to xss
And Cookie to CSRF also makes sense
What makes me puzzled is that it seems like implicitly said that cookie is not vulnerable to xss, but isn't it also vulnerable to xss?
If I can run a script on other's browser, I think I might be able to just send request to server & get important data cause browser automatically attach cookies & I dont' need to do anything to get authenticated.
If a cookie is set with the httpOnly flag, it cannot be accessed from Javascript (injected js cannot read or write such cookies), so it is not possible to steal the cookie value if it's httpOnly. This is very relevant for a session cookie. In this case, this cookie is not affected by XSS. Note that this is solely because of the httpOnly flag - cookies without httpOnly are affected by XSS, because they are accessible to Javascript.
Any cookie (regardless of flags*) will still be sent with any request to the server it was received from, but that is the realm of csrf, actually, it is the fundamental problem in csrf. If anybody (from any website) makes a request to a server, any cookie for that server will be sent, and the attacker can exploit csrf if there is no protection. That's why you need protection against csrf if you have cookie-based authentication.
Also note that if the page is vulnerable to XSS, than any csrf protection is useless, because xss can be used to read the token, wherever it is stored.
*Sidenote: the new SameSite cookie flag changes this, but that is only supported by Chrome.

JWT + cookies + HTTPS + CSRF

I already worked with JWT on mobile app but I will implement it on a website for the first time for the authentication and I have a little thing I still didn't understood :
if I use JWT token with localStorage, XSS attacks are possible
if I use JWT token with cookies, CRSF attacks are possible
..., but if I use JWT token over HTTPS with httpOnly+secure cookies and a token lifetime of 1 month, are CSRF attacks still possible in this case ?
I see all over the web for custom token with cookie or custom token with localStorage or JWT but I didn't explicitly get the answer of httpOnly+secure cookie + JWT + HTTPS + the need of CSRF.
If you are using JWT as an authentication token, it should be stored as a cookie marked httpOnly and secure, as apposed to using Local/Session Storage. As you mention, this protects against XSS attacks, where we are concerned about malicious JavaScript being injected into our page and stealing our session token.
A cookie marked httpOnly cannot be read by JavaScript, so it cannot be stolen in an XSS attack.
Local/Session Storage, however, can be read by JavaScript, so putting the session token there would make it vulnerable to an XSS attack.
However, making the session token cookie httpOnly and secure still leaves you vulnerable to CSRF attacks. To see why, remember that cookies are marked with the domain from which they originated, and the browser only sends cookies that match the domain to which the request is being sent (independent of the domain of the page the request was sent from). For example, suppose I'm signed into stackoverflow.com in one tab, and in another tab go to evil.com. If evil.com makes an ajax call to stackoverflow.com/delete-my-account, my stackoverflow authentication token cookie will be sent to the stackoverflow server. Unless that endpoint is protecting against CSRF, my account will be deleted.
There are techniques for preventing CSRF attacks. I would recommend reading this OWASP page on CSRF attacks and preventions.