Is there a way in spring to destroy a http session if another login attempt of a logged in user comes? - spring-boot

For our application with spring-boot (2.1.4) it is important to us that a user can only be logged in once.
This was relatively easy to configure and works great in relation with REST requests.
http
.sessionManagement()
.maximumSessions(1)
.maxSessionsPreventsLogin(false)
.sessionRegistry(sessionRegistry());
Much of the communication runs through websockets, and getting here starts our problem.
The view of our browser app changes when the websocket connection is disconnected. On the server side the websocket handshake is disconnected if the http session is invalid.
As I understand it, if a user logs in again with an already logged in user, the http session remains valid until the next REST request. I would like the http session to terminate independently from requests.
I have a workaround where I check every AuthenticationSuccessEvent if there are already sessions of this user and terminate them. This approach works, but I don't like it.
Thanks a lot for your help!

A relatively blind guess, but have you tried changing the sessionFixation? It should create a completely new session, without copying over old attributes, on an authentication attempt.
http.sessionManagement()
.sessionFixation().newSession()
;

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.

Spring MVC SPRING_SECURITY_SAVED_REQUEST causes continuous invalid sessions

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.

How do I properly secure a REST-like service using Spring Security based on cookies?

I read this article on using Spring Security to "secure" (password-protect) a REST-like service: http://www.baeldung.com/2011/10/31/securing-a-restful-web-service-with-spring-security-3-1-part-3/.
This solution is what I seem to want, however, I noticed that at the bottom of the article, the authentication process is based on a cookie. If you notice, after a user logs in, a cookie is sent back to the user, and the user keeps using this cookie on subsequent request to access the REST endpoints (see the curl commands).
My concern about this approach centers on security; meaning, what's to stop the user from sending this cookie to someone else for use or someone from copying this cookie and using the REST service without proper authentication?
Is there a way to set the cookie (or cookies) such that it is valid for only one user? For example, for only the IP that authenticated correctly? But even this is problematic, as multiple users may share one external IP address.
It looks like the code is just demonstrating how to maintain a session between requests, exactly as your browser would do, by storing the JSESSIONID cookie. So I think your question is really the same as "what's to stop a user from copying the session cookie from their browser and giving it to someone else?". Of course there is nothing to stop them doing that but why would they want to? The same argument applies to any kind of security token. There's nothing to stop them giving away their username and password either which would have the same effect.
In most cases a web service would be stateless, so it wouldn't use session cookies. But OAuth tokens and so on are just as sensitive, often more so since they usually have a longer life span.

Does this session/token authentication system make sense for my web api?

Today I implemented a session/token authentication system for my web api (http get/post rpc style), following this plan:
legend: action (param1, param2) : returnvalue1, returnvalue2
login (username, password) : sessionkey, token
requestA (sessionkey, token, paramA) : token
requestB (sessionkey, token, paramB) : token
logout (sessionkey, token) : void
The login action is sent over https, to protect the users data. You get a session/token combination, where one token is only valid for one request (you will always receive a new token on normal requests).
My thoughts behind this were about reducing the risk for a man-in-the-middle attack, sniffing your session key: if you are "lucky", the sniffed token has already been invalidated through your own subsequent request.
My backend and its unittests are perfectly fine, but i didn't think far enough - i finally ran into issues with asynchronous ajax calls, which defeat this one-time-token idea.
Is the added security worth not being able to process asynchronous requests?
One idea was to introduce a request-queue inside my ajax application - did someone do anything like that, and would you recommend it?
A probably less secure, but more convenient way would imho be not to renew the token for every request - allowing asynchronous processing, but keeping the initial https auth and add a strict lifetime to a session. I should also save the IP to the session server-side.
Did i miss other valuable options?
I am bound to existing username/password values, which with no exception have to work without changes with the new ajax app.
It appears to me that the token mechanism that you designed won't actually protect you from man-in-the-middle attacks. Imagine a man-in-the-middle intercepting every (non-HTTPS) request from the client, and replacing it with a different one that is then sent to the server. The token that the server returns to the man-in-the-middle can then simply be returned back to the client, and the client probably would not be able to tell that its request never arrived at the server.
Is there a way you can simply do all the requests over https? Https offers a fair amount of protection from man-in-the-middle attacks, provided that you use proper certificates, and use highly random session keys that are not valid for too long.
Any subsequent requests after authentication that are made in plain text (read HTTP) should be considered insecure and prone to any attack you can imagine.
If your goal is to secure the communication between the client and your server HTTPS is a must for the whole session. Additionally you will want to make sure you change the session cookie after the client moves from HTTP to HTTPS (I'm assuming here that you are doing some sort of redirection if the original request is to HTTP). This is a common error that leaves the client vulnerable to a session stealing attack.
Rails does something similar to the mechanism you are describing. They call their tokens authenticity tokens. However my understanding is that the primary purpose is to do flow control or double-click protection instead of actually securing the communication.
I think HTTPS and binding the Session to the clients IP and regenerating the session id from time to time (maybe every 5 requests) will secure your API. Adding the request/token mechanism will improve security, but is no longer a must have, imho.
One problem I see upcoming with the request/token system is, if a request failed or no answer is recieved, how can the client restart communication? It has no valid request token and if your API works correctly, it will reject any request following :)

Can you help me understand this? "Common REST Mistakes: Sessions are irrelevant"

Disclaimer: I'm new to the REST school of thought, and I'm trying to wrap my mind around it.
So, I'm reading this page, Common REST Mistakes, and I've found I'm completely baffled by the section on sessions being irrelevant. This is what the page says:
There should be no need for a client
to "login" or "start a connection."
HTTP authentication is done
automatically on every message. Client
applications are consumers of
resources, not services. Therefore
there is nothing to log in to! Let's
say that you are booking a flight on a
REST web service. You don't create a
new "session" connection to the
service. Rather you ask the "itinerary
creator object" to create you a new
itinerary. You can start filling in
the blanks but then get some totally
different component elsewhere on the
web to fill in some other blanks.
There is no session so there is no
problem of migrating session state
between clients. There is also no
issue of "session affinity" in the
server (though there are still load
balancing issues to continue).
Okay, I get that HTTP authentication is done automatically on every message - but how? Is the username/password sent with every request? Doesn't that just increase attack surface area? I feel like I'm missing part of the puzzle.
Would it be bad to have a REST service, say, /session, that accepts a GET request, where you'd pass in a username/password as part of the request, and returns a session token if the authentication was successful, that could be then passed along with subsequent requests? Does that make sense from a REST point of view, or is that missing the point?
To be RESTful, each HTTP request should carry enough information by itself for its recipient to process it to be in complete harmony with the stateless nature of HTTP.
Okay, I get that HTTP authentication
is done automatically on every message
- but how?
Yes, the username and password is sent with every request. The common methods to do so are basic access authentication and digest access authentication. And yes, an eavesdropper can capture the user's credentials. One would thus encrypt all data sent and received using Transport Layer Security (TLS).
Would it be bad to have a REST
service, say, /session, that accepts a
GET request, where you'd pass in a
username/password as part of the
request, and returns a session token
if the authentication was successful,
that could be then passed along with
subsequent requests? Does that make
sense from a REST point of view, or is
that missing the point?
This would not be RESTful since it carries state but it is however quite common since it's a convenience for users; a user does not have to login each time.
What you describe in a "session token" is commonly referred to as a login cookie. For instance, if you try to login to your Yahoo! account there's a checkbox that says "keep me logged in for 2 weeks". This is essentially saying (in your words) "keep my session token alive for 2 weeks if I login successfully." Web browsers will send such login cookies (and possibly others) with each HTTP request you ask it to make for you.
It is not uncommon for a REST service to require authentication for every HTTP request. For example, Amazon S3 requires that every request have a signature that is derived from the user credentials, the exact request to perform, and the current time. This signature is easy to calculate on the client side, can be quickly verified by the server, and is of limited use to an attacker who intercepts it (since it is based on the current time).
Many people don't understand REST principales very clearly, using a session token doesn't mean always you're stateful, the reason to send username/password with each request is only for authentication and the same for sending a token (generated by login process) just to decide if the client has permission to request data or not, you only violate REST convetions when you use weither username/password or session tokens to decide what data to show !
instead you have to use them only for athentication (to show data or not to show data)
in your case i say YES this is RESTy, but try avoiding using native php sessions in your REST API and start generating your own hashed tokens that expire in determined periode of time!
No, it doesn't miss the point. Google's ClientLogin works in exactly this way with the notable exception that the client is instructed to go to the "/session" using a HTTP 401 response. But this doesn't create a session, it only creates a way for clients to (temporarily) authenticate themselves without passing the credentials in the clear, and for the server to control the validity of these temporary credentials as it sees fit.
Okay, I get that HTTP authentication
is done automatically on every message
- but how?
"Authorization:" HTTP header send by client. Either basic (plain text) or digest.
Would it be bad to have a REST
service, say, /session, that accepts a
GET request, where you'd pass in a
username/password as part of the
request, and returns a session token
if the authentication was successful,
that could be then passed along with
subsequent requests? Does that make
sense from a REST point of view, or is
that missing the point?
The whole idea of session is to make stateful applications using stateless protocol (HTTP) and dumb client (web browser), by maintaining the state on server's side. One of the REST principles is "Every resource is uniquely addressable using a universal syntax for use in hypermedia links". Session variables are something that cannot be accessed via URI. Truly RESTful application would maintain state on client's side, sending all the necessary variables over by HTTP, preferably in the URI.
Example: search with pagination. You'd have URL in form
http://server/search/urlencoded-search-terms/page_num
It's has a lot in common with bookmarkable URLs
I think your suggestion is OK, if you want to control the client session life time. I think that RESTful architecture encourages you to develop stateless applications. As #2pence wrote "each HTTP request should carry enough information by itself for its recipient to process it to be in complete harmony with the stateless nature of HTTP" .
However, not always that is the case, sometimes the application needs to tell when client logs-in or logs-out and to maintain resources such as locks or licenses based on this information. See my follow up question for an example of such case.

Resources