📜 ⬆️ ⬇️

Store the session on the client to simplify application scaling (3rd of 12 articles on Node.js from the Mozilla Identity team)

From the translator: This is the third article from the cycle about Node.js from the Mozilla Identity team that deals with the Persona project. This article is about Persona’s method of storing session data on the client.




Static websites scale well. They are easy to cache, and do not need to constantly synchronize data on multiple servers.

Unfortunately, most web applications need to store state information in order to offer users personalized pages. If users can register on the site, then we need to store the session. The most common way is to set a cookie with a random session ID, and to keep the details on the server.
')

Site scaling with state storage


If you need to scale such a site, there are three options:

  1. Replicate session data between all servers.
  2. Use a central repository to which all servers will access.
  3. Assign a specific server to each user.

All of these approaches have disadvantages:

  1. Replication degrades performance and increases complexity.
  2. Central storage limits scaling and leads to additional delays.
  3. Binding users to specific servers leads to problems when the server is shut down.

However, after thinking a bit, you can come up with a fourth way: store all session data on the client.

Storing sessions on the client


Storing session data in a browser has several obvious advantages:

  1. Data is always available, regardless of which server serves the client.
  2. No need to store state on the server.
  3. No need to synchronize status information between servers.
  4. You can add new servers very easily.

But there is one big problem: the data stored by the client cannot be trusted. For example, if you store a user ID in a cookie, then it can override it and get access to someone else’s account.

Although this problem seems insurmountable, it has a solution: to store data in a secure container. Thus, it is no longer necessary to trust the client - he has no opportunity to substitute them unnoticed.

In practice, this means that the data in the cookie must be encrypted and signed with the key stored on the server. This is exactly what the client-sessions module does.

node-client-sessions


The node-client-sessions for Node.js replaces the standard middleware modules of the Connect session framework and the cookie-parser . Here's how to include it in a simple application for Express:

const clientSessions = require("client-sessions"); app.use(clientSessions({ secret: '0GBlJZ9EKBt2Zbi2flRPvztczCewBxXK' // set this to a long random string! })); 

You can then set the property values ​​of the req.session object:
 app.get('/login', function (req, res){ req.session.username = 'JohnDoe'; }); 

and read them:
 app.get('/', function (req, res){ res.send('Welcome ' + req.session.username); }); 

To close the session, use the reset() method:
 app.get('/logout', function (req, res) { req.session.reset(); }); 

Instant Persona Session Closing


One of the main disadvantages of storing sessions on the client is that the server can no longer close sessions on its own.

When storing session data on the server, it is enough just to delete session data from the database, after which all cookies on all clients will indicate a non-existing record. When data is stored on the client, the server cannot be sure that the data has been deleted in all browsers. In other words, it is not so easy to synchronize the new state of the server (the user has ended the session) with the state on the client (the session is open).

To lessen the severity of the problem a bit, client-sessions keep the session lifetime in the cookie. Before unpacking data from an encrypted container, the server will check if they are expired. If yes, then he will ignore this data and will consider that the session is closed.

Although the scheme with setting the time of life works well, especially if the time is not very long, in the case of Persona we needed a way to immediately close the session on all clients if the user changed the password.

We still had to keep a small amount of state on the server. We did this by adding one field to the database table on the server and to the cookie.

Each API call that accesses session data now reads this field in the database and compares it with a similar field in the cookie. If they do not match, the session is considered closed.

Excessive access to the database is, of course, not very good, but, fortunately, we already had to read from the table with user data on almost every call, so the session identifier could be obtained without unnecessary overhead. So that you could quickly start experimenting with the module, we wrote a small demo application .




Source: https://habr.com/ru/post/196018/


All Articles