This article will be comparing SuperTokens to Node’s most popular session management library –
express-session. The comparison will be done using a point system, where a point will be awarded to a library’s
score if it performs well in a given metric. Here are the metrics we will be using:
We explore how both libraries mitigate against different session attacks below. For a
background on why session security is important, read our other blog post. The attack vectors for sessions are: the frontend, over the network and the
backend.
In an XSS attack, an attacker can maliciously inject JavaScript into a website on the
victim’s browser. The injected code reads and transmits session tokens to the attacker.
Exclusively using HttpOnly cookies to store auth tokens disallows any JavaScript running on
the browser from reading them, preventing token theft via XSS. Both SuperTokens and express-session protect
against this attack.
SuperTokens: 1, Express-sessions: 1
This attack can be solved easily by using long length tokens that have a high amount of
entropy. Both SuperTokens and express-session use long length tokens, mitigating this attack.
SuperTokens: 2, Express-sessions: 2
While this attack is mostly preventable using HTTPS, it can still be successfully executed –
especially in corporate environments (Check out this tool) where access to the internet is controlled via an HTTPS proxy. As such, there is
no full proof method to prevent this attack and we can only attempt to minimize the damage.
Express-session uses just one long lived session token. Hence, for each API request, the
frontend needs to send this token to the backend for authentication purposes. If a MITM attack is being carried
out, any request the app makes will expose this critical token to the attacker who can then use it to gain access
to the victim’s account – potentially for months.
SuperTokens uses two auth tokens: one short lived access token, and one long lived refresh
token. The recommended lifespan of the access token is <= 1 hour. For most API calls, only the access token is
sent over the network. This means, a MITM attacker will likely only get hold of the access token, which would
grant them access to the victim’s account for a limited amount of time. SuperTokens is also able to detect token
theft in the event that the attacker gets hold of the refresh token.
It’s clear that SuperTokens minimises damage during this attack.
SuperTokens: 3, Express-session: 2
The attack consists of inducing a user to authenticate themselves with a known session ID,
and then hijacking the user-validated session by the knowledge of the used session ID.
Session fixation can be prevented by changing the auth tokens upon successful user login.
While express-session provides the regenerate function, it’s the developer’s responsibility
to call this and make sure any session data is carried forward. Since many developers use passport JS (which
doesn’t call this function – see here) for login purposes, this attack vector goes unresolved.
In the case of SuperTokens, the only way to associate a userId to a session is by creating a
new session. This means that the auth tokens change too, mitigating this attack.
SuperTokens wins a point.
SuperTokens: 4, Express-session: 2
In the context of express-session, a secret key is used to sign the cookies. This signature
helps the backend ensure that any incoming session was in fact generated by it (though I’d argue that the same
can be achieved by simply having a longer sessionID, even without a signature). These session IDs (SIDs) in the
signed cookies are not guessable, so if the attacker is only able to steal the secret key, then there is not much
they can do, but if the attacker also gets hold of SIDs from the storage layer (which is likely since they managed
to get the secret somehow), then they can hijack the sessions associated with those SIDs quite easily.
SuperTokens also has a secret key. This is used to create a JWT access token that is sent to the client. Here the secret key is necessary and used to
ensure integrity of any incoming token. If the key is compromised, then the attacker would be able to change any
JWT and impersonate any user in the system (as long as they know that user’s user ID).
The only way to minimise the impact of a stolen key, is to keep changing it:
As we can see, both libraries have their pros and cons on this front, and none is a clear
winner. So a point goes to both.
SuperTokens: 5, Express-session: 3
Express-session stores all session IDs in plain text. This means that if an attacker was to
get hold of this information (and assuming that they also got hold of the secret key – which is quite probable if
they have access to the db), they could easily hijack the session of all currently logged in users.
SuperTokens stores only the hashed[2]
version of the session tokens. This means that if anyone (even application developers) gets a hold of them and its
corresponding session data, they will not be able to use it to hijack any user’s session.
SuperTokens clearly wins this point
SuperTokens: 6, Express-session: 3
Express-session does nothing to prevent this. On the other hand, SuperTokens has CSRF
protection which is enabled by default for all non-GET APIs. By simply passing a boolean value to the function
that does session verification, one can enable / disable CSRF protection for different APIs.
There are two aspects to this attack:
SuperTokens follows both these practices. It uses two tokens (access and refresh tokens),
which keep changing frequently, and also has token theft detection using the IETF
recommended method. Below is the session flow that shows the usage of the tokens:
Meanwhile, express-session uses one long lived token and has no means to detect token theft.
Below is the session flow for express-session:
SuperTokens wins this point as well.
SuperTokens: 8, Express-session: 3
Session authentication is performed in most APIs. Hence, it’s necessary that the methodology
for verifying a session is as efficient as possible in terms of time complexity. When talking about latency, it is
important to realise that I/O based operations, like reading from a database, are the bottlenecks.
Time complexity: Express-session does a database call for each verification
of a session, and also provides no caching functionality out of the box (unless using redis storage). Since
SuperTokens uses a JWT as its access token, most calls to verify a session do not require any network operation.
SuperTokens gain’s a point here.
SuperTokens: 9, Express-session: 3
Correctness means that the code works as expected in normal and edge case situations. Based
on our evaluation, we found that express-session is not thread safe. The specific failure case is that it is
possible to bring back a revoked user session in certain scenarios:
For SuperTokens, we’ve made sure that once a session is removed from the database, it never
comes back. We do this by enforcing that all update operations never insert a row in case the primary field
(session ID) doesn’t exist..
SuperTokens: 10, Express-session: 3
In the context of sessions, a good user experience means that we enable long lived sessions
so that app users do not have to keep logging in repeatedly. Both Express-session and SuperTokens enable this, so
it’s a tie.
SuperTokens: 11, Express-session: 4
Completeness: Session management is tightly tied to user management. This
means, given a session, one should be able to retrieve the associated user information, and given a user ID, one
should be able to retrieve all the associated sessions. While express-session allows you to get user information
given a session ID, going the other way around would require customisations. On the other hand, SuperTokens have
both way bindings.
SuperTokens: 12, Express-session: 4
Complexity in initial setup: SuperTokens is more complex to set up than
Express-session is, albeit for good reason – it adds more security and it also has more features. This point goes
to express-session.
SuperTokens: 12, Express-session: 5
Community support: Since Express-Session is an older library and is being
used by a lot of developers, it has great support and a big presence on sites such as StackOverflow. SuperTokens
does not yet have equally good community support. Express-Session wins a point here.
SuperTokens: 12, Express-session: 6
Dedicated support: For many industries like banking and healthcare, having
dedicated support for third party tools being used for critical applications is compulsory. Unlike
Express-session, SuperTokens provides dedicated support and hence gains a point.
SuperTokens: 13, Express-session: 6
Runtime cost: Higher costs are incurred by higher processor and RAM usage.
Express-session, being a library for Node, doesn’t require extra resources to run in terms of processors or RAM.
Meanwhile, SuperTokens is run as a separate process. Due to this, it requires slightly more RAM and processing
than express-session does. Hence, express-session gets a point here.
SuperTokens: 13, Express-session: 7
External costs: Express-session is completely free to use. SuperTokens has
a community (free) and a paid version. Some of the features discussed above are only available in the paid
version, so it’s only fair to give a point to express-session for this metric.
SuperTokens: 13, Express-session: 8
Internal Costs: Express-session is a relatively simple library, which means
that as apps scale, eventually, more and more work needs to be put into “scaling” / changing the session
management system. Examples of changes are:
I realise that not all the above points will be of concern, but even if one of them does end
up being true, that can add significant costs to an organisation / project simply because of how expensive
developers are – especially one experienced enough to work on session security.
It’s clear that if using express-session, it’s very likely that an organisation would run
into this issue eventually because it’s a simple and an old library (so more unlikely to change). On the
other hand, SuperTokens is a new solution that has in its roadmap many features so that eventually, as apps scale,
its developers do not have to worry about changes to their session management system. So SuperTokens gain’s a
point here.
SuperTokens: 14, Express-session: 8
We can see that SuperTokens clearly wins out on the metrics we have chosen. Not just that,
it’s only going to get much better over time as we expand on the number of frameworks we support as well as add
more amazing features! Overall, it is much more secure and complete. Of course, I am a little biased towards
SuperTokens because I am one of the contributors to the library, but I think I have compared the two libraries
fairly. If you find that there are some metrics I have missed where Express-session performs better, or if you
have any general feedback, please drop a comment or send us an email.
To learn more about Sessions, please visit our other blogs and our website:
Written by the Folks at SuperTokens — hope you enjoyed! We are always available on our Discord server.
Join us if you have any questions or need any help.