How long is Spring temporary CSRF token expiration time? - spring

I enabled CSRF with spring security and it is working as expected.
I read Spring official documentation about CSRF
http://docs.spring.io/spring-security/site/docs/3.2.7.RELEASE/reference/htmlsingle/#csrf
I also read this tutorial about CSRF with Spring and AngularJS
http://www.codesandnotes.be/2015/07/24/angularjs-web-apps-for-spring-based-rest-services-security-the-server-side-part-2-csrf/
What Spring Security does is that it sets up a temporary session for
that. So basically it goes like this:
The client asks a token with an OPTIONS request.
The server creates a temporary session, stores the token and sends back a JSESSIONID and the token to the client.
The client submits the login credentials using that JSESSIONID and CSRF token.
The server matches the CSRF stored for the received JSESSIONID and, if all is green-lighted, creates a new definitive JSESSIONID and a new session-based CSRF token for the client to validate its requests after the login.
As I have understood, when you are not logged in, you can get your first CSRF token by sending an OPTIONS request on any API endpoint, for example /api/login
Spring will then create a CSRF token bound to a temporary session (temporary CSRF and JSESSIONID cookies)
Thus, if I ask the CSRF token than wait a few minutes and finally try to login, the CSRF token may have expîred and I will have to ask another one.
I couldn't find how to configure the temporary Spring session expiration time and I couldn't find what was its exact default duration.
Does anyone has any information about that ?

creates a new definitive JSESSIONID and a new session-based CSRF token
this is a session fixation strategy.
there are at least 2 strategies for CSRFToken generation.
per session
per request
The default behaviour should be per session. It means that as long as session would be alive one and only CSRFToken would be bound to it (but this can be changed).
after successful authentication, because of session fixation, a new session would be created with new CSRFToken.
Thus, if I ask the CSRF token than wait a few minutes and finally try
to login, the CSRF token may have expîred and I will have to ask
another one
this is wrong. it would stay as long as session would be active.
I couldn't find how to configure the temporary Spring session
expiration time and I couldn't find what was its exact default
duration
temporary session is called temporary, because it would be valid until authentication and would be replaced by a new one. But same timeout policy is applied to them as for common session. you can configure session-timeout in web.xml using session-config. the default value of Tomcat is 30 minutes.

Related

JWT in Cookies - do I need a refresh token?

I'm implementing security for my React SPA using Spring Security on the backend. After a lot of reading, I opted for the following approach :
HTTPS everywhere
POST /login takes credentials returns JWT_TOKEN & XSRF_TOKEN in cookie form. I build the JWT_TOKEN myself whereas Spring Security handles the XSRF_TOKEN. Both cookies are Secured and SameSite=Strict. The JWT token is HttpOnly.
Subsequent API calls require the X-XSRF-TOKEN header. This is read from the aforementionned cookie. Both are sent and Spring Security compares them. JWT is automatically sent and checked in a Filter.
Every time a XSRF token is used, Spring Security generates a new one to prevent session-fixation attacks
XSS protections are applied by Spring Security
So now I'm wondering about refresh tokens. I'm reading a lot of contradictory info out there. Do I need them with this setup? If so how best to handle this ?
Many Thanks
In general, as its name says, the refresh token changes from one token to another. Typically they are used in OAuth protocol-based authentication. They are useful when an access token has expired, but the user's session is still valid.
First, JWTs are a great choice for access tokens. They have claims that match the access tokens requirements, such as: exp, iat, jti, sub, etc. But, when using a cookie-based authentication there is no need for access tokens and possibly no need for JWT.
As you said, your JWT_TOKEN is being set as an HttpOnly cookie, which means that only the server has access to it. JWT is useful for sharing the initial state between the client and server, and vice-versa. If your server is just taking it to look up the database, you don't need a JWT, you are just using a session concept, and keeping session data on a JWT may not be a good practice.
Second, if your authenticated cookie data will live at /login and die at /logout, there is no need for refresh tokens. Refresh tokens are an exchange key for short-life access tokens. Instead, your cookies keep the session live and don't need to be exchanged by something else.
For example, if the user uses the /login route to exchange your username and password for one short life access_token. He may need the refresh_token to get a new access_token without needing to send his username and password again.
If you are using the OAuth protocol or similar, refresh tokens are essential to provide a more seamless experience for your users and avoid the inconvenience of repeatedly having to re-enter their credentials. But even on OAuth, they are not mandatory.

CSRF Token keeps refreshing every 2nd request. (Spring boot 3 and Next.JS)

I've been creating a Spring boot 3 and Next.JS app with Spring Security. Been having some problems with the "Set-Cookie" header being refreshed on every 2nd request I make to the backend. I can illustrate the problem as:
Make a request to /finances (with XSRF-TOKEN provided post-successful login)
The request goes through (contains all the necessary data for a valid request [CSRF cookie, JWT token, etc..]). The response contains a "Set-Cookie: XSRF-TOKEN= ...." header without the TOKEN.
I refresh the page (make a new request using the useEffect hook) and the CSRF cookie appears again, a new one.
If i refresh the page (make a new request using the useEffect hook) again, the CSRF cookie is deleted.
And so on.
I pass the cookie value on every request to the backend (whenever it is available) and the backend operates on it correctly. So there are no problems with the token validation.
I've also read that the spring security will provide a new XSRF cookie/value if the request from the client does not provide a cookie of the same name.
Could some one please help?
I've tried configuring the response on the backend to attach a new cookie with the same value, and also saving the cookie value in the session storage for later use. None of the options seem to work.
Making two requests to the server would solve the issue (probably) but that would not be an optimal solution. To the problem.

How are CSRF tokens stored on the server side ( by spring security or tomcat)

This question is not about how CSRF tokens works, but is rather about they are stored on the server side.
In short, CSRF tokens are generated by server and injected in to the web page/form. When the form is submitted the csrf token is extracted by the server and compared to the one saved on the server. So far so good.
From this earlier posting - CSRF token value when same page is opened in two tabs on same machine?
Here's the excellent answer which explains that -
The server will create a CSRF token (token1) and store that token in
the HttpSession. The CSRF token (token1) is also be embedded in the
form on the client side. The client is also given a Session ID
(session-id1) which is stored in a cookie.
When the client submits the form, it sends token1 and session-id1. The
server will then use session-id1 to look up the HttpSession and get
the expected CSRF token for that session. It will compare the expected
CSRF token to token1 and if the values do not match, the HTTP request
will be rejected.
and
If you open the same form in another tab, the browser will still have
access to the Session ID (session-id1). That form will get the same
token (token1) that was associated with session-id1.
In the end, there is only one CSRF token (token1) that is used in both
tabs.
Bit more info can be found in the quoted reference, but it fails to explain the server side part.
The above leads to more questions -
If another form (form2) is opened by user in a different tab - then what CSRF token will it get, will it be same as that for the first form(form1) ?
To explore and unsderstand better, I want to know where and how the CSRF tokens are stored in the backend when using spring security (unlike Session Cookies which are generated by Servlet Container, I am assuming that CSRF tokens are generated by Spring Security module). Is there just one CSRF token per session, which is used accross every form and every tab or there are several CSRF tokens.
Please clarify as much as you can... every drop counts

CSRF token value when same page is opened in two tabs on same machine?

From my understanding, when CSRF is enabled on server side, the server creates a token (say token1) and injects it in to the form and saves the same in the cookie of the client browser.
When the client sends the form request to the server, it sends the csrf token (token1) from browser cookie and also send the same token as in the form. The server validates the request by checking that the token in cookie and the token in form match and then processes the request.
Now, if i open the same form in another tab, will the server generate another token (token2) and inject it in to the form and cookie. Then, in the cookie, token1 will be overwritten by token2. So the submission of the form in first tab will not work in this case? But from experience i see that the submission of form in tab 1 still succeeds.
So can some one explain how it's succeeding in the above scenario??
Since you have added the Spring Security tag, I will describe how Spring Security uses the Synchronizer Token Pattern to protect against CSRF attacks.
the server creates a token (say token1) and injects it in to the form and saves the same in the cookie of the client browser.
That's not exactly what happens. The server will create a CSRF token (token1) and store that token in the HttpSession. The CSRF token (token1) is also be embedded in the form on the client side. The client is also given a Session ID (session-id1) which is stored in a cookie.
When the client submits the form, it sends token1 and session-id1. The server will then use session-id1 to look up the HttpSession and get the expected CSRF token for that session. It will compare the expected CSRF token to token1 and if the values do not match, the HTTP request will be rejected.
If you open the same form in another tab, the browser will still have access to the Session ID (session-id1). That form will get the same token (token1) that was associated with session-id1.
In the end, there is only one CSRF token (token1) that is used in both tabs.
You can find more information about protection against CSRF attacks in the Spring Security reference documentation.

Spring Security set CSRF in login response with new session token

I'm using spring security in my spring boot application. I have a front end single page app that logs in via rest. I have no problem logging in, but once I've logged in, my session token changes, BUT THE CSRF TOKEN DOES NOT.
Is there any way to force spring security to set the csrf token since the old token associated with the un-authenticated session token will not work with the new authenticated session token?
I'm storing the CSRF token in a cookie, and sending it back from the client in the header of every state altering request. I can't login and logout without an intervening request (non-post) to retrieve the csrf token. This seems like a crock.
SO a simple solution is to redirect the login request once it's successful. This puts the request through another loop through the security filter chain ensuring a new CSRF is added to the new session token. A good night sleep does wonders.

Resources