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:
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?
It's good to know which measures prevent which security holes.
You are correct that JavaScript is not well suited for encryption because there is no place to store a secret. There are also no good encryption libraries because you shouldn't be doing encryption in JavaScript.
The session key can serve as the authentication key. If you're using TLS your connection is secure and an attacker can't know the session key. Additionally, JavaScript doesn't need to know the session key. Cookies, by default, are sent with every request. And you can set the cookie to be an http-only cookie. You don't have to do this, but it does add another layer of security.
You can give the session cookie a very long expiration time so that it essentially works like a secret API key. The browser will take care of storing the cookie securely. It is advised to rotate the session key often, typically at the start of every new session and when authentication information changes (like a password reset).
CSRF-tokens prevent replay attacks. It's definitely recommend to secure a modification request with a CSRF-token. You don't need a CSRF-check for every request, just requests that modify sensitive information (such as your login credentials, or in your case: transactions). For CSRF-tokens you can use the same approach as the session key: store it in a cookie.
The key part is that JavaScript doesn't need to know about any of this.
One important thing that I'm sure you realize as well is that any keys or nonces you generate must be cryptographically safe. Don't use low entropy functions.
So:
You don't need to encrypt the userid or email, TLS does that for you already. Additionally you can send the password as well, you don't need to send it separately in step 3. We're not going to do any encryption in JavaScript. All encryption is handled by TLS/HTTPS alone.
If you have a separate authentication server (like a single sign on), this approach is fine. Else you can skip this step.
You don't need this.
The server doesn't need to decrypt anything, encryption is handled by TLS. How you store the password is a topic on it's own but I think you've got it.
Ok. Again, the client shouldn't encrypt anything.
Send just the session key. It's is enough.
Revised is:
Client sends login credentials. Connection must be secure.
Server verifies credentials and sends authentication token as cookie and keeps track of the authentication token is a session list.
For every request:
Client includes authentication token. This happens automatically if you use cookies.
Server verifies authentication token and possibly generates a fresh token that the client will use from then on.
Mobile apps should be considered as public clients. This means they should not store any secret. Whatever the encryption algorithm you will use, nothing prevent the client credentials from being compromised.
That is why the OAuth2 Framework protocol defines the Implicit grant type flow which allow public client interaction and do not need any client authentication. You may also consider the RFC7636 to protect the issuance of the access token.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With