I just started a development of my first REST API in .NET. Since it will be stateless I will use tokens for authentication:
Basic idea (System.Security.Cryptography):
- AES for encryption + HMACSHA256 for integrity
- token data will consist object with properties: username, date of issuing and timeout
- database will hold username, hashed password and HMAC hash
Login:
- check if credentials are valid (username, compare hashed password to db value)
- if true, encrypt data object
- use HMAC on generated token and store it to database
- return token (without HMAC) to user (cookie/string)
Request to method which requires authentication:
- user sends token with each request
- token is decrypted
- if it is expired, error
- if not expired use HMAC and compare username + generated hash with db values
- if db check valid, user is authenticated
The way I see it, this approach has following pros:
- even if db is comprosmised, it does not contain actual token (hash cannot be reversed...)
- even if attacker has token, he cannot increase expiration by updating fields since expiration date is in the token itself
Now firstly, I wonder if this is good approach at all.
Besides that I still didn't figure out, where to store AES and SHA256 keys on server (should i just hardcode them? If I put them into web.config or use machine key than I have a problem in case of load balanced servers,...).
And lastly where do I store AES IV vectors, since Crypto.CreateEncryptor requires it for decryption? Does it mean that users have to send token + IV with each request?
I hope this makes any sense and I thank you for answers in advance.
UPDATE:
Ok, now I did some more research and came down with this solution:
- token will contain originally specified data (username, date of issuing and timeout)
- token is generated with encrypt-then-mac (it includes AES encrypted data, IV vector + tag of these 2 values for authentication, generated with HMACSHA265)
- token tag will be written to db
- user will be authenticated if:
- tag is valid (token authentication)
- data can be decrypted
- token has not expired yet
- tag matches the one written in database
- user is not blocked in database (token invalidation on demand)
- keys will be stored in web.config separate section. Same keys will have to be on every server (per application of course)
I didn't use FormsAuthenticationTicket because in .NET there are following issues:
- same keys are used for different purposes (machinekey for view states, resources and formauthtickets)
- mac-then-encrypt, used by .NET is not considered as safe as encrypt-then-mac
- no built in way to invalidate token before it is expired