I have written a database-based authentication framework for webapps I am planning to program in the future.
The framework is implemented by using the plpgsql-language of a PostgreSQL-Database and therefore the extension pgcrypto is used to encrypt sensitive information.
If the user of a webapp authenticates (so the webserver fires up sth.) like
select authenticate('firstname.lastname@example.org', 'login-token')
the database returns
False, Invalid user / login token
True, Successfully logged in, session-id
The session-id is transmitted to the webserver in cleartext, so a cookie can be created, while it is saved in the database by applying a hashing algorithm, which comes with the pgcrypto-extension. This is a kind of bcrypt-implementation (the PostgreSQL-Documentation is kind of vague). The session-id is combined with an unique salt (one per session-id).
So in the session-table you find sth. like
|primary key|user-id|bcrypt(session-id)|other information
The question is about the function which is used to check if the session-id is valid and which user it is about. This function is fired, when the user presents a session-id to the webserver, who is in turn to validate this session-id.
If there is no additional identifier the select-part has the following problem:
For each row in the session-table the hash-function must be applied to the given session-id.
This works like
- select a row of session-table
- read the salt and hash the user-given session-id
- compare the result with the hash of the actual row
- repeat until found a match (return True) or the end of table is reached without any match (return False)
This is kind of slow (slower if more sessions are there).
So the idea is to use an identifier, which is unsensitive to do the following (pseudocode)
- select get_user_by_session_id(user-given-dentifier, session_id)
- select hash from session-table where identifier=user-given-identifier
- check if hash_function(session_id) = hash
This has the advantage, that only one crypto-operation is necessary, instead of one for each row in the session table until the valid one is found.
In the current design there are two possible identifiers I could give to the user.
- A static unique member_key which is generated at the registration for each user.
- The salt used for encrypt / hash the session-id
I would go for the salt, because I wanted to use the member_key for identification purposes (support calls) or something else. I don't see any problems with this, because of the following reasons:
- in general the salt must not be encrypted and can be saved in plain text
- only the webserver and the user himself sees the salt (webserver during transmit, user in the cookie)
- the attacker only can get this salt by intercepting the connection - if he does this, he also get the session-id in plaintext
Do I miss anything? Does the static member_key have any advantages over the salt?