3

My application consists of a nodejs back end API but I am also developing a "reference" implementation of a JavaScript client, which is a backbone SPA.

First of all; the API accepts only HTTPS requests, in case an HTTP request reaches the server it completely ignores it and also (depending on tenant configuration) invalidates the password provided on that insecure request.

My server is stateless and I am using only HTTP(S) basic authentication. I provide two ways of authenticating a request:

1- Sending credentials on header Authentication: base64('Basic ' + user:password)
2- Sending an authenticated request using method 1 to GET /users/current which returns a token that is an encrypted string* containing: username + '|' + timeOfTokenExpiration. Client then sends only header Authentication: base64('Token ' + username:returnedToken) thereafter.

*Encryption is done with OpenSSL's aes-256-ctr algorithm, and key is user's password hash

Method 1 can be used for a straight server-to-server communication, but it is not suitable for a JavaScript client since the user would have to insert his credentials on every request, what is infeasible.

Storing user credentials on browser's local storage would solve this issue but would keep the user indefinitely logged, creating another possible security threat. Also I am not sure how secure it is to store credentials in clear text on browser's memory.

By using method 2 the JavaScript client would send only one authenticated request and then store encrypted credentials on local storage, after a given amount of time it has to revalidate user credentials since it will eventually expire and server will no long accept requests from that token.

At server side I check authenticity of a method 2 request by retrieving user's password hash and trying to decrypt it. After decryption I check if decryptedString.split('|')[0] === username.

Is this a safe/good approach?

2
  • I check authenticity of a method 2 request by; retrieving user's password: are you storing passwords unhashed ? Dec 7, 2014 at 23:05
  • No, they are hashed. I encrypt the token with the password hash actually. Dec 7, 2014 at 23:17

1 Answer 1

3

There's a problem with you method 2: if you use the user's hash as the encryption key for the token - and the only thing verified in the server is whether or not the token decrypts (no other validation is performed in the token) - then whoever has the user's hash can authenticate as that user. This voids any protection* granted by hashing the user password, you might as well store it as plain text...

I'd suggest not bothering to encrypt the token (since it has no sensitive data in it), only signing it with a secret known only to the server, and verifying that the signature is valid when the user tries to authenticate using method 2. Note that by "signature" I mean either a digital signature using a private key known only to the server, or a HMAC using a similar secret. Remembering not to store this secret in the DB itself, but in either a hardware module, memory-only or - if you has to - a configuration file.

* To be fair, at the very least the password itself will still be protected - only your system will be vulnerable, other systems where the user has reused that password won't be negatively affected.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .