This question already has an answer here:
I'm designing an API with token authentication.
I don't want to store tokens as plain text in the database, for the same reason user passwords are not stored as plain text: if the database gets compromised, the attacker should not be able to extract any usable token from it.
My current plan is to generate tokens 40 chars in length, composed this way:
- the first 20 chars would be the token "ID" (the primary key in the database)
- the next 20 chars would be the token "password"
Upon generation of the token, I would send the full token to the client, and store in my database:
- the token ID
- a SHA1 hash of the token password
This way, my database only holds half of the actual token sent to the client, and can only verify tokens, not retrieve them.
I'm not planning to add a salt: as I understand it, the whole point of the salt is to prevent hash table / rainbow table attacks againt commonly used or short passwords, while in my case passwords are totally random, with enough entropy (67 possible chars, 20 chars in length = 4×1036 combinations). Unless I missed something, adding a salt in this case would be the same as creating a longer random password.
Also, I'm not planning to use an expensive hashing technique such as Bcrypt, as it would be too expensive: unlike user authentication, where the user authenticates once and then gets a session ID, the token is the only method of authentication here and is going to be sent with every single API call; a 50ms hashing method is just not acceptable here. I don't consider having an expensive hashing technique particularly more secure, for the same reason exposed in the previous point: the password is random with enough entropy, so even with a powerful hashing machine, it would still take billions of years to bruteforce.
Is there any flaw in my approach?
The only one I can think of (provided someone gets access to the database!), is if a vulnerability is found in SHA1, so that it becomes feasible to find an input that gives a given hash as output (this somehow happened to MD5, I heard). But I guess this is the same thing for every hashing algorithm out there, Bcrypt included?