Application Session Stores on CloudBees - java

I'm trying to fully understand when/how to use CloudBees' notion of application session stores.
After reading that article, my understanding of them is that they provide a way to make multiple instances of your appserver share persistent session variables. That way, you can load balance between each server, and it doesn't matter which instance your user gets redirected to; each server instance has the same shared session states (for all users).
So first, if my understanding is incorrect or slightly misinformed, please begin by correcting me!
Assuming I am more or less correct, then I have the following questions:
How does this hurt performance or memory utilization? I would imagine that if each server has to share the same cached session data for all users, it would get kind of bulky and perhaps even pricy...
Is there a way to programmatically CRUD session states (i.e. flush the cache, inspect it with JMX, etc.)?
Can someone provide a concrete use case for this feature, just so I'm positive I "get it"?
Thanks in advance!

Session store let you replicate the HttpSession around the cluster, so that you can scale-out application load on multiple instances, without having to stick a user to a specific server (this is the other option you can use : configure sticky session)
By nature, serializing HttpSession data has some impacts on performance, but as it uses a memcache backend this is minimal. This also mostly depends on the amount and size of objects you store in user session. Also, please note this require you explicitly put object in HttpSession after any attribute change, even the object was retrieved from session - this is a general API issue with JavaEE clustering.
You can't programmatically query the session store (you could with the adequate memcache client code, but this doesn't make much sense)
Two concrete use cases
application distributed on multiple nodes, with session distributed around the cluster, and without sticky session so that load is actually distributed for ALL user
Application te be redeployed can't suffer user session to be lost, to ensure a continuous 0 downtime service. version N+1 application will then retrieve httpsession data from version N, need to be compatible from serialization point of view, but connected user won't notice the redeployment and version upgrade

Related

Sharing session data between two war files

I have two war files such as war1 and war2
If am login the application, the session will be created in war1 and from that if am navigate to war2, there i need the same session data.
I tried crossContext=true in context.xml of server from that i can access the data by storing it in servletContext.
But the issue is once i logined the screen in chrome the session data will be stored in servletContext and the data will maintain till the application is running.
If am giving the same URL in another browser like IE here also, i can get the servletContext data so instead of navigate to login page the corresponding screen will be opened
Kindly suggest me how can i overcome this issue in java?
Is there any way to findout browser switching or incognito window mode of the browser in java?
Note: am using tomcat server
I have never dealt with your exact configuration problem, but even if you can make this work on a single Tomcat instance, you might have problems should your two web applications ever be distributed across multiple Tomcat instances.
So, I am going to suggest that you actually use a database to store state which needs to be passed between the two applications in a safe and reliable way. Note that the database approach also scales nicely in a distributed environment, so long as you have a single logical database.
While session replication indeed can be done in Tomcat (see here) I really suggest you to avoid this type of issues by eliminating the session altogether.
This session replication is an approach that was somewhat common before ~15-10 years, but nowadays when we have a lot of servers running in parallel to serve user requests and have elastic clusters, this approach is not good enough because basically it doesn't scale well.
There are many ways to achieve what you want, though:
Use a shared database to store the session information. Add some session Id to the response and require the client to pass this id back into all subsequent request along the session. Then execute a query to the Database by this Id and retrieve all the session information.
This solution also doesnt really scale well, but then you can shard the session information if the db permits to do so...
Use Redis/Aerospike to save the session information of the currently connected user. somewhat like DB approach, but since redis run in-memory it will be much faster. In general, this approach can be used in conjunction with 1 where redis is an in-memory cache.
Encrypt the session information or even just sign cryptographically and send back to client. Client will have to supply this information along with the request without knowing which server will actually serve this request.
Without delving into cryptography I'll just state that encryption can be done if you don't want client to see the session information (despite the fact that this is the user whose information is supplied) and signature is used to prevent tempering the data (while sending it back to server).
The data can be supplied to server from client via Header or cookie for instance.

Spring session lazy deserialization

I have the following situation, i have a microservice architecture with an api gateway and multiple downstream services, some of these have an independent session and this causes my system to throw expired session exception on random service calls.
Since we cannot rewrite these services from scratch we started by introducing hazelcast so that all services can share the same session.
the problem now is that when a service writes an object of a class that other services don't have in their classpath a deserialization exception is thrown.
to solve this i was thinking that if only the attributes that get accessed from a service get deserialized i could probably avoid the exception and everything should work fine.
Do you know if this is at all possible with spring session, or maybe can suggest another solution that would allow me solve the initial problem?
here is a sample project to reproduce my problem: https://github.com/deathcoder/hazelcast-shared-session
I believe I got what's happening: Spring-Session-Hazelcast by default store session updates locally until request completed & when request completed, before returning the response, send everything to the cluster using EntryProcessor. EntryProcessor requires object classes available on the member who stores that session record and since data is distributed, it's possible some other member stores a session created in another instance. According to what you're saying, not all nodes are identical, don't contain all classes & this causes serialization exception.
What you can do, you can use User Code Deployment feature to deploy those missing classes to other members: https://docs.hazelcast.org/docs/3.11/manual/html-single/index.html#member-user-code-deployment-beta
If you're changing object that you're storing in the session, you can set class-cache-mode to OFF to prevent not caching them but sending with each operation.
Please try & let me know if this solves your problem.
I would try to avoid sessions in the API layer in the first place. They scale poorly. And synchronizing sessions is even less scalable.
Try using access tokens instead, for example a JWT token. A token should contain enough user identity information to load the resources necessary to process the transaction (the resources can be cached).
As for the other state in the session - microservices are self-contained from the process perspective, so all intermediate results should be persisted to the database. But of course I don't know the details of your particular application, so this is just a general thought.

Servlet in-memory session storage

Most servlet containers seem to store HttpSession data in-memory. I wonder if this might cause a problem if, say, 500 users are logged into a servlet-based web app at the same time. Let's assume I store two values per user, one boolean value isLoggedIn and one integer value userRole. Should I be worried about potential excessive memory consumption by the web app? Up to now, I've mostly done development in PHP where most frameworks let you save session data in an SQL DB.
Is there any realistic chance that in-memory storage might cause a problem? Maybe there is a formula to calculate RAM usage per active user session.
If your session data is large, yes you should worry about it. Tomcat has a persistence manager that lets idle sessions be paged out to a database.

Explicitly set JSESSIONID

So, I'm in the middle of building an application where I want the user to be able to send a link to another user and work on the same data. There is little need to persist the data for more than 15 minutes and I want the application to not have to rely on a database.
I have a few variables which I am currently storing in a HttpSession.
Ideally I'd like to be able to set a parameter "sid" in the URL, and use that to set the session ID on the second client's browser - the one that's received a link with the SID.
Unfortunately, there seems to be no way to change the SID of a current session once it's been set up.
The only solution I've come up with so far is referring to the doGet() with a HttpPost.setHeader("Cookie", "JSESSIONID="+ getSessionId()) method, and getting the data with a specific session that way, but this seems pretty clunky.
Any suggestions?
EDIT
This has seemingly turned into a discussion about the wisdom of setting two users up to have the same session so session vars may be kept the same. Note that a non-db, ie light weight solution was what I was looking for. PHP allows you to arbitrarily set a session ID to do this, but I'm deploying to Tomcat in this instance. Something which allows lightweight sharing of a few parameters, that's it...
What I've done, then, is to set context vars using context.setAttribute(). Ugly as sin, but all I can come up with, unless anyone has any better ideas.
This approach has some security issues because you are simulating [session hijacking] with it 1:
In computer science, session hijacking, sometimes also known as cookie
hijacking is the exploitation of a valid computer session—sometimes
also called a session key—to gain unauthorized access to information
or services in a computer system. In particular, it is used to refer
to the theft of a magic cookie used to authenticate a user to a remote
server. It has particular relevance to web developers, as the HTTP
cookies used to maintain a session on many web sites can be easily
stolen by an attacker using an intermediary computer or with access to
the saved cookies on the victim's computer (see HTTP cookie theft).
Better approach is to set your data in a way that both users can approach it from their sessions. If you are using single server you can do that with some global data within a server. In clustered or cloud environments you'll need some common storage for that (ie. database, global cache, etc.)
EDIT
You are on a right track to share data among two users with different sessions.
There is one context per "web application" per Java Virtual Machine
where an attribute allows a servlet container to give the servlet
additional information.
Attributes are meant to be used to share data inside container among servlets of the same web application.
For clusters:
In the case of a web application marked "distributed" in its
deployment descriptor, there will be one context instance for each
virtual machine. In this situation, the context cannot be used as a
location to share global information (because the information won't be
truly global). Use an external resource like a database instead.

Does the Play! framework have any built in mechanism to prevent session hijacking?

I've read that the play framework solves the session fixation issue by hashing the session id with the application key, but does it provide any mechanism to prevent session hijacking, or is this left up to the implementor?
The play documentation has a good section on security, so rather than duplicate, here is a link - http://www.playframework.org/documentation/1.2.4/security.
It covers
XSS
SQL Injection
Session security
Cross site request forgery
Some you have to implement yourself, others you don't.
Your specific question about session hijacking is automatic.
The session is a hash of key/values, signed but not encrypted. That
means that as long as your secret is safe, it is not possible for a
third-party to forge sessions.
No, there is no built in way to prevent the hijacking of a session as soon as one is able to capture the session cookie (through sniffing/man in the middle).
There are some ways to make it harder, e.g.:
using only https
setting application.session.httpOnly in application.conf
One approache to make it harder is:
- store the ip/user-agent/resolution/other stuff or a hash of that also in the session.. in your controller you then check if the user that accesses your site still recreates the same hash... the only real problem is with people that are using a proxy that e.g. changes the ip on the fly because of clustering.
A little trick you could try to use: (works only in recent browsers)
When a user logs in, store some stuff in a HTML5 local storage. Modify your Ajax calls to supply this information from the local storage. If the information is missing/invalid, you can invalidate the whole session. But you'll have to make sure, that the checks only get applied against requests from HTML5 browsers.
hope this helps a bit.

Categories

Resources