Spring MVC SPRING_SECURITY_SAVED_REQUEST causes continuous invalid sessions - spring

I have a Spring MVC App and I have an issue with invalidated sessions.
The app performs AJAX requests that are all authenticated/tied to a session (hold a JSESSIONID)
So here's what happens. Let's say I'm in the app authenticated with a session. If I go into Tomcat and invalidate that session, then the next time an HTTP request gets made, Spring forwards me to the login page. Once I login again, Spring authenticates me fine, but then a number of my AJAX requests get HTTP 403 errors, continuously.
If I go into the HTTP Headers of the requests that get the 403s, I notice they have 2 JSESSIONIDs, one of the authenticated session, the other one of a session that holds only this attribute:
SPRING_SECURITY_SAVED_REQUEST DefaultSavedRequest[<OLD URL>]
So these sessions are not authenticated sessions so they are causing Spring to return a 403.
The issue is that this persists until I kill the browser (on some mobile devices that doesn't even work, and I have to go into settings to clear the browser cache).
Any suggestions?
this is a big problem because it's happening when Sessions invalidate themselves because of TTL, and we're stuck with users who get booted out, log back in and still get 403s, forever, until they clear the cache.

One thing to note is that Spring Security invalidates the existing session when you login and creates a new one, copying the contents of the old one across. This is intended to create a new session identifier to avoid session fixation attacks. You can try disabling this feature to see if it is related to your problem. It sounds like these are the two sessions you are talking about.
However if there are two JSESSIONID headers in the request then it sounds like a problem on the client side. You should work out why your client is sending two values. Also, it sounds like there may be an issue with Tomcat on the server side if you are still able to read the contents of the previously invalidated session.
Also check that Tomcat isn't sending two JSESSIONID values in the login response. There was an issue ages ago where it was doing just that, but it's unlikely you are running such an old version of Tomcat.

Related

understanding JSESSIONID with basic authentication

I went through some resources about JSESSIONID. They say that HTTP and web-servers are stateless. Ok fine, I know this. But then they say- to add a state to these, sessions are used. And there is a session created JSESSIONID by web servers(in java applications). JSESSIONID helps web servers to recognize if the request is coming from the same previous user or a new user. But, this created a doubt in me:
For basic authentication(for example), we send username password with each request, along with JSESSIONID. So, what additional benefit does JSESSIONID adds to that request, if we still need to send credentials with each request. What is the benefit of remembering the client-requests(the idea of using session-cookies)?
Any real-world example, please.

Prevent session from being replicated when JSESSIONID cookie copied

Background: I have a javaee webapp deployed on tomcat which uses form based authentication. When the web server receives a login request, it sends the request to a dedicated authentication service which validates user login (User id and password). After successful authentication user's session is maintained in the web server.
Problem: I have written a simple webpp source code here, to simulate the scenario. On successful login the current HttpSession instance is invalidated and new instance is created. For each request for a post login page, the session is validated. A new JSESSIONID cookie is set which is used to identify the user during the session until session is expired or user logs out. This cookie can easily viewed in browser's dev tools. If I copy the cookie and set this in a different browser via JavaScript (document.cookie="JSESSIONID=xyzz") and then try to access a post login page, the server identifies it as a valid request and session is validated successfully. The post login page is served without user being challenged for user Id and password.
POC: User opens chrome and enter the URL http://localhost:8080/mywebapp/ and logs in with admin and pass1234. On successful log in the home page http://localhost:8080/mywebapp/home is shown. Now the JSESSIONID cookie is copied and set in FireFox. User enters http://localhost:8080/mywebapp/home in Firefox and is shown the home page without being challenged for userId and password.
Question: How can this be prevented wherein same session is getting replicated over multiple browsers?
You can't prevent this specific case of simply copying the cookie from your own browser (or by copying the cookie value from a HTTP payload copypaste/screenshot posted by an ignorant somewhere on the Internet). You can at most prevent the cookie getting hijacked by XSS or man-in-middle attacks.
This all is elaborated in Wikipedia page on the subject Session Hijacking of which I snipped away irrelevant parts (either already enforced by Servlet API, or are simply not applicable here).
Prevention
Methods to prevent session hijacking include:
Encryption of the data traffic passed between the parties by using SSL/TLS; in particular the session key (though ideally all traffic for the entire session[11]). This technique is widely relied-upon by web-based banks and other e-commerce services, because it completely prevents sniffing-style attacks. However, it could still be possible to perform some other kind of session hijack. In response, scientists from the Radboud University Nijmegen proposed in 2013 a way to prevent session hijacking by correlating the application session with the SSL/TLS credentials[12]
(snip, not relevant)
(snip, not relevant)
Some services make secondary checks against the identity of the user. For example, a web server could check with each request made that the IP address of the user matched the one last used during that session. This does not prevent attacks by somebody who shares the same IP address, however, and could be frustrating for users whose IP address is liable to change during a browsing session.
Alternatively, some services will change the value of the cookie with each and every request. This dramatically reduces the window in which an attacker can operate and makes it easy to identify whether an attack has taken place, but can cause other technical problems (for example, two legitimate, closely timed requests from the same client can lead to a token check error on the server).
(snip, not relevant)
In other words:
Use HTTPS instead of HTTP to prevent man-in-middle attacks.
Add a checkbox "Lock my IP" to login form and reject requests from different IP associated with same session in a servlet filter. This only works on users who know themselves they have a fixed IP.
Change session cookie on every request. Interesting at first sight, but breaks when user has same website open in multiple browser tabs/windows in same "session".
Not mentioned, but make sure you don't have a XSS hole anywhere, else it's very easy stealing cookies.
Last but not least, I'd like to make clear that this problem is absolutely not specifically related to Servlet API and the JSESSIONID cookie. All other stateful server side languages/frameworks such as PHP (PHPSESSID) and ASP (ASPSESSIONID) also expose exactly the same security problem. The JSESSIONID was previously (decade ago orso) only a bit more in news because by default it was possible to pass the session identifier along in the URL (which was done to support HTTP session in clients who have cookies disabled). Trouble started when ignorant endusers copypasted the full URL with JSESSIONID inside to share links with others. Since Servlet 3.0 you can turn off JSESSIONID in URLs by enforcing a cookie-only policy.
<session-config>
<tracking-mode>COOKIE</tracking-mode>
</session-config>
See also:
How do servlets work? Instantiation, sessions, shared variables and multithreading
How to prevent adding jsessionid at the end of redirected url
remove jsessionid in url rewrite in spring mvc
What you have stated is called session hijacking. There are many good answers on how to prevent it.
Using same Jsession ID to login into other machine
we can use Encryption or hide JSESSIONID using Browser control.
Thanks

Grails: CookieTheftException with anonymous access

I have a grails server and an iOS client that communicate over HTTPS via POST messages. I'm using PersistentTokenBasedRememberMeServices to ensure that the user doesn't have to enter his password all the time. This doesn't seem to work as the session is lost continuously and the user has to login again. The server logs show that a CookieTheftException has occurred with message "Invalid remember-me token (Series/token) mismatch".
Not all server actions require a logged in user. Some can be accessed anonymously and this may be the root of the problem. When the user accesses restricted server actions, the session is maintained, but not when accessing unrestricted actions.
Here's my config in Config.groovy:
grails.plugins.springsecurity.rememberMe.cookieName = 'SomeRememberMeName'
grails.plugins.springsecurity.rememberMe.persistent = true
grails.plugins.springsecurity.rememberMe.alwaysRemember = true
grails.plugins.springsecurity.rememberMe.persistentToken.domainClassName = 'com.myapp.PersistentLogin'
grails.plugins.springsecurity.rememberMe.tokenValiditySeconds=31*24*60*60
I added some traces in the iOS client and noticed a couple of things. First of all the JSESSIONID cookie doesn't have an expiration time, which means it isn't saved in the client like the rememberMe cookie. Can I force it to have an expiration time or is that even a good idea? Secondly I noticed that sometimes the rememberMe cookie that I receive from the server is empty. That may be just because a CookieTheftException was thrown.
Since all of the post message bodies are encrypted with 256-bit AES, I'm not really worried about cookie theft at this time. I just need to get this to work.
I tried adding the following to my config to ensure that the session would be always updated even when accessing unrestricted actions:
grails.plugins.springsecurity.useSessionFixationPrevention = true
grails.plugins.springsecurity.SessionFixationPrevention.migrate = true
grails.plugins.springsecurity.SessionFixationPrevention.alwaysCreateSession = true
I don't even know what these all mean. I just liked the "alwaysCreateSession" part and figured that I need to enable session fixation prevention in order for that setting to have any effect. Will it still always create a session if I set useSessionFixationPrevention to false?
Any help is appreciated.
If you are using PersistentTokenBasedRememberMeServices, your "remember me" token will change after every HTTP request.
Unfortunately that means that requests will only authenticate if your browser makes exactly one request at a time, and browsers often don't do that. If there are 4 few images on a page, the browser will send out 4 simultaneous requests, each with the same "remember me" token. Only the first request will authenticate, because after Spring Security processes the first request, it changes the token. When Spring Security tries to process the next request, it throws a CookieTheftException.
That's the typical scenerio for the CookieTheftException when using PersistentTokenBasedRememberMeServices.
Here's a link that explains some things you can do about it: Grails Cookie Theft Exceptions
There's also an open issue with the Grails Spring Security Core plugin that discusses this problem: Remember me functionality fails intermittently with CookieTheftException: Invalid remember-me token
The JSESSIONID stuff is probably a red herring. If you're using PersistentTokenBasedRememberMeServices, your authentication won't need a session.

Spring do not update session for ajax polling

We are currently running into a problem with session time outs on one of our Spring web applications. The session never times out because we have a continuous ajax request polling the server. Is there a way to tell spring to ignore this request and not update the session so that time out works as expected?
You could run a timer, equal to your session timeout, along side the continuous ajax request that would log the user out if the page never refreshes. Another idea would be to host the URL that you are hitting in a separate web application on the same domain. I'm not sure if Spring has something built in for what you are doing.
I thought about this some more. You could implement your own session registry that ignores the Ajax URLs. Basically you wouldn't set the last accessed time for a user in the session registry if the URL matched one that you defined in your ignore list or filter defined in the Spring Security filter chain.
See SessionRegistry

How do websites generally log users out automatically when session expires?

How do websites generally log users out and send them to the log in screen automatically when a user's session expires? Is this done through ajax or running async handlers? Can you give me a bit of an explanation.
Banks and such use a client-side timeout via javascript, or something similar. Really, though, the server handles the actual session, so if you disabled the client-side logic it would act as if you were attempting to make transactions while logged out.
Use a cookie as well as a session.
Cookie must be set when a session is
started.
If the cookie is present but the
session is gone, redirect to the
login screen.
If there is no session and no cookie
do nothing
(pardon me if you can't do that because I never used ASP and basing my answer on my PHP knowledge)
Typically, you set an expiration timestamp on your session ID cookie. When the cookie fails to be sent, the client is logged off (no given session ID).
This method is often combined with JavaScript and another timestamp token. When the timers start running down, a notification is sent that allows the user to "refresh" their session... essentially, making a request before the session timestamp expires.
The "refresh" request could be anything, even something as simple as an image load.
If you are using Tomcat you can use its built in <security-constraint> mechanism within your web.xml definition. All of the timing, login screen, and page redirects are handled by Tomcat with little effort on your part other than definitions.
Oh, IIS... nevermind.

Resources