Authentication & Sessions¶
This document gives a quick overview over the way that Fietsboek uses sessions
and authenticates users, going a bit into the technical details and reasoning
behind them. Fietsboek mostly uses Pyramid’s authentication facilities,
using hashed passwords in the database, and combining both the
SessionAuthenticationHelper
and the AuthTktCookieHelper
.
Password Storage¶
Fietsboek stores passwords as a salted scrypt hash, using the implementation
in the cryptography library. The parameters Fietsboek uses are taken from
the cryptography
documentation, which in turn takes them from RFC 7914:
SCRYPT_PARAMETERS = {
"length": 32,
"n": 2**14,
"r": 8,
"p": 1,
}
We note that the recommendation is from 2016, so a slightly increased value of
n
could be chosen to stay around the 100 ms target. The Go documentation
mentions n = 2**15
. The reason why this is not updated yet is that it would
require logic to update password hashes when users log in, which has not been
implemented.
The randomness for the salt is taken from Python’s built-in secrets module, using high-quality random sources.
User Fingerprint¶
The cookie signature makes it hard to forge valid authentication tokens in the first place. However, even with the signature mechanism in place, there are (at least) two possible issues if we leave away the extra fingerprint:
Firstly, while no “new” authentication cookies can be forged, a legitimate cookie that is saved might lead to a wrong user being retrieved. For example, if someone saves their authentication cookie, then deletes their user account, and the database re-uses the ID for the next new user, then the old authentication cookie could be used to gain access to the new account.
Secondly, as sessions and cookies are client-side, we cannot influence them from the server. Therefore, there would be no way to invalidate a specific cookie, or all authentication cookies for a specific user (short of changing the application secret and invalidating all cookies). To provide a “Log out all sessions” functionality, we need a way to invalidate sessions remotely.
To solve those problems, we add a cryptographic hash (more precisely, a 10 byte SHAKE hash) to the authentication cookie, which is formed over the following data points:
The user’s email address
The hash of the user’s password
A random session secret, specific to each user
This means that if any of those data points changes, the fingerprint will change, and old authentication sessions and cookies will no longer be valid:
If the user changes their email address, we consider this a relevant change, and require the user to login again.
If a user changes their password, all sessions are also invalidated, and the user needs to login again.
If we want to invalidate the sessions without setting a new password (e.g. because the user requests it), we simply set a new random session secret for the user.
We note that the fingerprint only offers 80 bits of security (which is rather low), but the fingerprint is not the main line of defense against forged logins: the main source of security for forged logins is the cookie signature. The fingerprint only ensures that no “user mixups” can occur. So not only would you need to brute-force the correct 80 bits of fingerprint, but for each fingerprint you also need to generate a valid signature.