So there's already an example for authenticating by mutating "login" and returning the auth token as part of the response - does anyone have any ideas how I might use a secure cookie instead? I'd really strongly prefer to use this if I can, as it's an extra barrier against sessions being hijacked by an XSS attack on my relay app. I'm using Akka HTTP.
Ideas I've had so far:
Set the token value on the context as a mutable value during query execution, then grab it out inside a map call (bad)
Set the token on the response as in the example, then in a map call modify the response to remove the auth token and set it as a cookie instead (less bad, but not exactly great).
Is there something better than I haven't thought of?
A 'secure cookie" I assume you are referring to a signed cookie?
Signatures do not hide cookie contents, the contents are simply treated as being tampered if the signature failed to validate, but the cookie is public/readable anyway
If the cookie itself being present is how a session will re-auth for each subsequent request (maintain session, aka; 'session riding' in attacker speak) then it being signed or not is functionally no different than losing an 'auth token' (assume you mean an OAuth2/OIDC/JWT but not an API Key?) via XSS
So far we have discussed 'auth' in the sense of authorisation (authz), that having a token authorises you to make the request, the response trusts you are who you claim - i.e. the system of using a cookie or a token that implies this is merely a trust-based system, no real authorisation 'mechanism', only unverified trust in the cookie or token
To apply an authorisation 'mechanism' for signed cookie, or token, there must be a mechanism the server can use to verify the sender is the authentic (auth in the sense of authentication aka authn). Does your application code apply one-time authn and 'bearer' token/cookie trust without authz? Bearer authz means you have th 'thing' and if you have it you are authorised. Because Bearer authz is a blind, unverified, method of authz that if the 'thing they bear to you is stolen anyone can be a bearer and gain authz.
Or do you want to apply an authz mechanism?
If you are doing bearer only, the signed cookie or auth token is equivalent security, from the attackers perspective.
If you are interested in applying authz mechanisms so the token can be verified for authenticity, this mostly requires the requester to have a secret to 'sign' the token or cookie with, a secret they have that signing can prove they have it without sending it over the wire to the server with the request (and expose the secret).
To learn more about this start with OWASP Authz page (I contributed to) here https://cheatsheetseries.owasp.org/cheatsheets/Authentication_Cheat_Sheet.html
If this is no longer relevant, please accept the answer for other readers who come across it.
Related
I've been reading about it for a few days and I have two questions
1) If I store the access token in localstorage and the refresh token in an HttpOnly cookie, do I have to worry about XSRF? If the attacker cheats to make a request, the response is received by the good user. It is not bad that it requests a new acces token and a refresh token, the attacker cannot steal the content of the response. This is true ?
If the attack is XSS it can make the same attacks as if it also stored the access token as an HttpOnly cookie ... which is bad. But if you stored the refresh token in localstorage it would be very bad and you could update the access token.
With this approach I should not worry about XSRF, but if I store the 2 tokens in HttpOnly cookie I have to worry about XSRF (about the token to avoid XSRF) and XSS. And if they make a successful attack, they can only do evil the lifetime of the access token.
2) If my authorization server is a micro service and I access through an internal IP (10.x.x.x) I have to continue worrying about XSS but not XSRF, is this true?
Have you considered saving both the refresh-token and the access-token (or id-token) to secure, httponly cookies? I do this and it works great. I also sign my cookies, and double xor them.
In your middleware function, you can check the validity of your access-token. If the access-token is valid, permit the access of the resource.
If the access-token has expired, check the refresh-token for validity (as it may be expired). If it's still valid, issue a new access-token via a cookie and permit the user access to the resource.
If the refresh-token is also expired, the user has to re-login.
I think this area is often misunderstood, and generally I recommend:
Being very careful about risks, first and foremost
Once done, store access tokens in browser memory
Refresh tokens in cookies give you better overall options
A couple of relevant blog posts of mine:
Web Architecture Goals
Browser Token Security
Interested in feedback also ..
I've been reading about JWT, and from what I understand, it's a token that the server sends after a user logs in. The user will have to send that token with all future HTTP requests. This creates a stateless way for the server to verify a user's request.
Now what I don't understand is that if the JWT is sent in the header and marked as HTTP only, why is a CSRF token also needed for prevention of CSRF attacks? My understanding is that both JWT and CSRF tokens are tied to a user, and that a JWT would serve both purposes.
I understand that CSRF tokens are used so HTTP requests from other sites won't be accepted. How does a JWT not accomplish that? What separates a CSRF token from a JWT token, and allows it to accomplish that difference?
I've been reading articles on JWT's and CSRF tokens as well as the double submit method, but there is just something I can't seem to understand or I'm missing.
An authentication system based on tokens (JWT or random) stored in cookies is vulnerable to CSRF attacks, because cookies are sent automatically to server in each request and an attacker could build a harmful url link to your site.
https://yoursite.com/delete?something=1
To protect your site it is needed to use a CSRF token that your application must send in the following request (not in a cookie).
Alternatively you could store the JWT in localStorage and send it in a Authorization header, then your site is protected against CSRF, but it could be vulnerable to XSS attacks. Take in account always the security considerations of the technical solution you choose
Update ¿why storing JWT in localstorage could be vulnerable to XSS attacks?
See this comparison between storing tokens in localstorage and http-only cookies https://academind.com/tutorials/localstorage-vs-cookies-xss
An attacker could inject javascript code to read the token from the localstorage and send it to his own server. However, this type of attack is not possible with an http-only cookie because it is not accessible from javascript
All your questions are relative to the fact that a CSRF token in NEVER included in a cookie and that a JWT token MAY be sent in a cookie.
A JWT token can be sent:
1- in a cookie
2- in another type of header
3- outside the headers, in some POST attribute
4- outside the headers, in some GET parameter (not very common)
But for stateless authentication, you MUST use cookie (case 1).
So, for stateless authentication, you are prone to CSRF, with your JWT token. This is why you need to add some CSRF mitigation mechanism, based on some more information not included in a cookie, or not only included in a cookie.
All of this would not apply if you were accepting to implement a stateful authentication.
I am developing a REST application with its own authentication and authorization mechanism. I want to use JSON Web Tokens for authentication. Is the following a valid and safe implementation?
A REST API will be developed to accept username and password and do the authentication. The HTTP method to be used is POST so that there is no caching. Also, there will be SSL for security at the time of transit
At the time of authentication, two JWTs will be created - access token and refresh token. Refresh token will have longer validity. Both the tokens will be written in cookies, so that they are sent in every subsequent requests
On every REST API call, the tokens will be retrieved from the HTTP header. If the access token is not expired, check the privileges of the user and allow access accordingly. If the access token is expired but the refresh token is valid, recreate new access token and refresh token with new expiry dates (do all necessary checks to ensure that the user rights to authenticate are not revoked) and sent back through Cookies
Provide a logout REST API that will reset the cookie and hence subsequent API calls will be rejected until login is done.
My understanding of refresh token here is:
Due to the presence of refresh token, we can keep shorter validity period for access token and check frequently (at the expiry of access token) that the user is still authorized to login.
Please correct me if I am wrong.
A REST API will be developed to accept username and password and do
the authentication. The HTTP method to be used is POST so that there
is no caching. Also, there will be SSL for security at the time of
transit
This is the way most do it, so you're good here.
At the time of authentication, two JWTs will be created - access token
and refresh token. Refresh token will have longer validity. Both the
tokens will be written in cookies so that they are sent in every
subsequent requests
Storing the tokens in cookies I not dangerous in itself, but if you somehow get you JWT module on your server to read them from there you vulnerable to CSRF attacks where any webpage can trigger a users browser to send a form + you sites cookie to your server unless you use CSRF tokens. So generally they are stored in localStorage and "manually" added to request headers every time.
On every REST API call, the tokens will be retrieved from the HTTP
header. If the access token is not expired, check the privileges of
the user and allow access accordingly. If the access token is expired
but the refresh token is valid, recreate new access token and refresh
token with new expiry dates (do all necessary checks to ensure that
the user rights to authenticate are not revoked) and sent back through
Cookies
Apart from the cookie dangers, it seems safe.
Provide a logout REST API that will reset the cookie and hence
subsequent API calls will be rejected until login is done.
You don't even need to make an API call, you can simply just purge the cookies or the localStorage object and make sure your client doesn't break on missing tokens.
The standard for the express-jwt module expects the tokens to be in its own "Authorization: Bearer [Token]" header, which I would strongly recommend over cookies. The localStorage API is available all the way back to IE8 so you should be good.
Edit:
First, it's important to know the difference between XSS and CSRF attacks since they're often believed to be the same thing.
XSS is when users get unsafe JS running on your domain in other users browsers when that happens neither JWT in localStorage or sessions and JWT in cookies are safe. With httpOnly flag on cookies, you can't directly access them, but the browser will still send them with AJAX requests to your server. If this happens you generally out of luck. To prevent this, make sure to escape all user input if it's sent to the browser.
If you load 3rd party JS with script tags or iframes this might compromise localStorage unless you are careful, but I haven't worked enough with this to help you here.
CSRF is only when other domains are trying to send normal HTML forms to your server by getting the browser to send cookies automatically. Frameworks prevent this by inserting unique random strings as hidden fields and checking them again when it's submitted. JWT's in localStorage is safe from this since each domain gets its own separate localStorage area.
But ultimately all this depends on if your service will be using one single domain, in which case httpOnly cookies will be plenty secure and easier to set up, but if you wanna spread your service out on multiple domains like api.domain.com + app.domain.com or add a native app you're forced to store you're JWTs in localStorage or some other native storage area.
Hope this helps!
I asked this question two years back and also accepted the answer. However, based on my experience and study in the last two years, I'd like to answer this just in case someone stumbles on this thread with the same question.
The approach mentioned in the question is similar to the "Resource Owner Password Credentials" grant type of OAuth 2.0. However, I think it is better to use the "Authorization Code Grant" type instead and Cookie to store the tokens instead of browser localStorage or sessionStorage. I have detailed my reasons, implementation points, security considerations and references in this StackOverlow answer.
Like OP I been using resource owner password grant.
I learned so much from Saptarshi Basu's other answer in a different post I think anyone looking into OAuth Code Flow should take a look at it, it has outlined a very solid approach to auth SPA and resource servers. It primarily relies on your backend(resource server) to handle authentication with the auth provider as a private client.
However, I will just add that people looking at implementing authentication with SPA should also consider OAuth Code Flow with PKCE. The main goal of PKCE is to allow public client such as SPA to authenticate directly with auth provider. All PKCE adds, is that when a SPA app initiates authentication, a hashed value is sent to the auth provider when the user is authenticated. And after user authenticate with the authorization provider, it redirects the user back to SPA with that hashed value as well as authorization code. Now, for the next part where the SPA calls auth provider to exchange code for tokens, instead of providing client secret, it has to provide the key that was originally used to create the hashed value. This mechanism guarantees the code cannot be used by someone who intercepted the code, and the SPA doesnt need to store a client secret like a server-side app does.
Now the only thing I'm not certain at this point is which is technically more secure, server-side authentication using standard Code Flow without PKCE or SPA authenticating directly using PKCE? Most resources I could find online currently describes and recommends the latter . However I feel that letting a private server side client handle authentication (as Saptarshi Basu described) might still be more secure. I would love to hear his opinion on this as well.
My understanding of refresh token here is:
Due to the presence of refresh token, we can keep shorter validity period for access token and check frequently (at the expiry of access token) that the user is still authorized to login.
Please correct me if I am wrong.
Assuming you're talking about using JWT as Bearer-token in OAuth (and I would strongly advice to follow the OAuth 2.0 protocol), that's right.
With an additional auth-time (timestamp of authentication) claim in your JWT, you could even drop the second token and sent your access- as a refresh-token (the auth-server could then issue a new access-token if token is valid & auth-time within allowed range)... but sure, it's also good to follow the standard ;)
Anyway, there are certain additional aspects (that tend to get difficult or are even against the fundamental ideas of JWT) you should consider before using JWTs as refresh-token, as this basically means you introduce long-living JWT:
do you need to have something like forced user logout/ token revocation by subject (e.g. if user got identified as fraudulent)?
do you need to have something like revocation of a specific token (e.g. if a user looses a device)?
...
Dependent on your use-case you should consider all the possible implications, long-living tokens have as they usually require you to introduce some kind of state on your server-side (e.g. to allow revocation/ blacklisting). Keep in mind the beauty and security of the JWT concept lies within JWTs being short-lived.
I'm building SPA app with server side rendering, using JWT-based authentication.
Current implementation is:
JWT token is issued and transferred to client after successful username and password verification
token is then stored in cookie (not HttpOnly) - the purpose of that is to avoid the need to login again after full refresh or closing page
logging out deleted cookie with token
Authorization header is attached to every API request if token exists
full SSL traffic
I can't store token in LocalStorage because of server side rendering, also the there is no HttpOnly because I need to access cookie in order to construct Authorization header.
What are the possibilities of stealing the token in such architecture?
One major risk is that any single cross-site scripting vulnerability in your application could be used to steal the token from the cookie, because it's not httpOnly (while I understand why that is the case). XSS in a javascript-heavy application like an SPA is very common and hard to avoid.
Also you're saying the token is kept in the cookie so that after closing the browser, the user is still logged in. On the one hand, that's bad practice, a user closing the browser probably expects being logged out. On the other hand, this means the cookie is persisted to disk, so it is much easier for an attacker to steal it from the client.
Another thing that comes to mind is cross-site request forgery (CSRF), but if I understand correctly, authentication is actually based on the Authorize header, where the token is copied in each request. If that's the case, CSRF is not an issue for you (but it would be, if sending the token in the cookie was enough).
So at the very least, I think you should
not use a persisted cookie for the token
try to minimize the chance of XSS (eg. by automatically scanning your code, but that will never be 100%, also by carefully choosing secure by default technologies)
make sure auhentication is based on the Authorize header and not the cookie
Still mainly because of the XSS risk, I would probably not recommend doing it this way in a security-critical application.
I need to implement an authentication scheme for a RESTful architecture. From several articles which I have read include basic Authentication using HTTPs and Session management using Cookie.
However I'm not well understanding the use of cookie. What i understands is that user first sends credentials. The server checks if the credentials are Ok. If yes, the server generates an authorization token and place it in the cookie. Onwards, on each and every request, server checks the validity of the token in the cookie.
But how does the server know that the content of the cookie is valid. Does it stores it somewhere and then it compares it??
The key point here is the authorization token. When generating one and sending back to the client, you store the auth token along with the username in let's say a database. You store the auth token in the cookie. The client on subsequent requests sends you the username and the cookie alongwith which contains the auth token. You verify this token against the supplied username and then perform the action per need.
However, do note that settings cookies makes your webservice call stateful and defeats the purpose of REST.
To achieve authentication/authorization, instead of setting the authorization token in the cookie, send it back as a response value. The client reads the value of auth token and then supplies the same in every REST request as a parameter of request body. Thus, you won't need to set cookies. This you may term as the toned down and simpler version of what is implemented in OAuth based API access.
I'm not an expert, but a good starting point to understand this is the section on Sessions in Hartl's book.
If I'm not mistaken it works as follows:
When the token is created, it uses a formula, e.g. the username and a unique user key (a salt) encrypted together. Both the username and the salt are stored in the database, and the salt is unique to that user. So, as you would do to compare if passwords match, to check the validity of the cookie you recreate the token and compare it to the one in the cookie. If it matches, then the right user is logged in and therefore authorised.
Hope this helps, or at least points you in the right direction :)