Monday, April 25, 2011

Secure (transient) storage of passwords for external APIs that don't support OAuth

My latest project, OboxApps.com, a mobile app suite for LogicBoxes (LB) and Resellerclub (RClub) users, has to deal with the the awkward situation of storing the users credentials to make API calls on their behalf.

Searching turned up some great answers by ircmaxell on how to deal with situations like this:
  1. PHP 2-way encryption: I need to store passwords that can be retrieved
  2. Encoding cookies so they cannot be spoofed or read etc

For increased security, I wanted the storage to be transient (duration of the session) and did not want to store the password on the server. So this is what I came up with:
  • I ask the user for the API credentials over HTTPS.
  • Verify that the creds works by making an API call.
  • Generate a 128 character random salt.
  • Encrypt the password using the random salt with the method used in the Encryption class from answer 1 above.
  • Store the random salt and API username in the session.
  • Send the encrypted password to the client in a secure (HTTPS), httponly cookie.
The API credentials and the encrypted password cookie are transmitted over HTTPS to protect against any kind of sniffing and the httponly property of the encrypted password cookie ensures that client side JavaScript cannot access it through XSS attacks (although it is not supported by all browsers).

Additionally (as suggested by ircmaxell in a private conversation), I could also look at implementing the Secure Cookie Protocol (pdf) for the encrypted password cookie and ensure the salt is sufficiently strong by using a derivation function such as KDF3 on the random salt to prevent or at least curb brute force attacks against the key generator, but I think this is good enough for now.