I designed a simple library (golang) for use as session token for web applications. The idea is simple:
- the token will be 16-byte long, denote it as
- generate a random byte
m, put it into
- encode the expiration timestamp as a big endian uint64, append the lower 48-bit of it into
- append the big endian representation of
t(i.e. the token's first and last byte is same)
- encrypt the token with AES/CBC, using a random key, and all-0 IV.
- hex-encode the encrypted token, output the resulting 32-byte string as the final token
In my view, this scheme has the following pros and cons:
- does not use a token store, hence is very scalable, if the web application has a lot of concurrently online users.
- verification of the token is very fast, and does not use network operation, such as querying a database or cache service like redis.
Revokation of individual token is difficult. Currently, I use a "blacklist" to record revoked tokens, which of course is not in-line with my initial purpose of a system that does not consume memory. However, it is easy to revoke all tokens by simply generate a new random key.
My question here is: for my purpose is the system considered SECURE? In general, why most session tokens are stored in DB or cache service, and cryptographic tokens are rarely used (are they)?
Reply to comments:
- About the encryption key
In my scheme, the encryption key is randomly generated, and kept in memory, and is NOT SHARED to anyone. The login API use this secrete key to generate the token, and the validation function of other APIs use this key to check if the token is valid or not. The client or any other party do NOT know this key. If this key is re-generated (e.g. server program restart), all issued key is instantly unusable.
Also, chosen plain text attack is just like brute-force guess of the encryption key. If I need higher level of security, I may use AES/GCM or other way to prevent it, e.g. limit the rate of token validation by client IP address.
- About replay prevention
I don't know why we need "replay" prevention in access tokens. Common scenario is:
- use login api to obtain a token by authenticate use username/password (or otp, sms code etc). This is usually protected by HTTPS.
- In the life time of the access token, the client can use it to access any other APIs. The only thing we can probably increase the security is bind the token with the IP address of the client, however, in modern mobile networks, change of client IP is inevitable.
In summary, I don't really care about people sharing their access token. It is analogous to you give the door key of hour house to your friend. The only thing a system should prevent is thief, which is prevented by HTTPS, and illegal duplicate of your "key", which is prevented by proven AES algorithm.
- Other considerations/questions
- big endian vs. little endian: I just choose it arbitrarily. I will use little endian to improve performance. Thanks @SAI Peregrinus
- Why we need authentication in design of an access token? In theory, how can we prevent share of an access token, except by bind the token with visitor IP address?
- JWT or PASETO allow you to encode data directly into the token. But my naive token only encode an ID. Whether you should carry your data directly in the token, or just use your token as a key to query the server for your data, is a bigger design consideration, outside the scope of this post.
I updated the token library, now it uses standard AES/GCM with random IV.