We're in the process of migrating our MVC-based server application and making a REST-ful API through which calls will be handled.
I've been reading up on AES encryption and OAuth2 and decided to implement a solution grown form those concepts as follows:
- Client sends a request to log in providing a UserID or Email. This request is HMAC'd using an API Secret Key.
- The server checks if the UserID/Email matches an existing account and if it finds one, creates and stores a server nonce which it sends as part of the response to the client.
- The client creates their own client nonce and creates a new temporary key from the API Secret key and both nonces. It then sends a login request with a password encrypted using this temporary key [for added entropy and to avoid ever sending a password in plaintext].
- The server decrypts the password and HMAC using the latest nonce it has stored for this client on this platform [a mobile and a web client can have their own distinct nonces and sessions] and the client nonce which was sent in the clear, if the HMAC checks out it then validates the password against the database [PBKDF2 hashing and salting].
- If the request is valid and the password and UserID match records, a new Session Secret Key is created for that UserID on that platform and this Secret key is sent to the client and will be used to HMAC every API request fromt hat client henceforth.
- Any new non-login request would include an HMAC signature computed from the Session Secret key and randomized IV's.
All communication is handled through TLS so this is added security and not the only line of defense.
On the mobile apps this would work since you can hide the Mobile App's Secret Key on a config file and this gives some decent measure of security - [perhaps not a lot I'm not fully sure] but if we try to convert all the requests from our webpage to this form this would mean using Javascript to handle the client-side AES encryption and authentication and ... well as this article clearly explains, " if you store your API key in a JavaScript web app you might as well just print it out in big bold letters across the homepage as the whole world now has access to it through their browser’s dev tools."
I could use only the nonces as the API Secret key -- or forgo using AES encryption for those requests altogether and try to validate through other means such as CSRF tokens and making sure all the requests come form our own front end in some way - but this wouldn't work if we wanted to create an API that allows integration with other pages or services and even then, how would I go about securing the client's secret Session key?
The article suggests generating single-use cookies as a tokens but that's a limited solution that works for the poster's services but wouldn't for us. I want to be able to HMAC every request the user sends with a user-specific key that can expire and be reset and since the service will eventually handle money, I want request authentication to be locked down tight.
So what are my options?
Do I just ditch Javascript since it is doomed? Is there some way to store a secret key without exposing it clear as day hardcoded into the .js script? Should I generate a new temporary Secret key to be used for login calls only and send that to the user when they request the server nonce?
Also, the post I linked to first suggests using a cookie to store the Session key for the client and then access the key from JS. Is this ok or would that provide more holes than it seals?