

Ask HN: How to store user/pass securely in the browser? - geuis

I'm working on a web app that will let the user interface with a 3rd party site via my service. In order for my service to utilize the API of the 3rd party, it requires the username and password for each individual user's account. I don't want to store people's private information on my service though. Not only do I feel personally uncomfortable doing that when other services want me to, and I don't want to be like that, I don't want to be in a position where someone potentially hacking my service can get all of my users' info.<p>I will have SSL setup for all communications between the user's browser and my service, and the API servers for the 3rd party are also via SSL.<p>I know I can very easily store the user's U/P in a cookie on their local machine(s), but that in itself presents security problems for them.<p>So, I need to be able to store the U/P <i>somewhere</i>. I don't want to make it so the user has to retype their info every single time they use my service, because it then reduces the click-and-go functionality of my service to zero.<p>What's the best approach in this kind of situation? Am I missing something obvious, or do I just have to bite the bullet and take the least-onerous option that's available?
======
cperciva
First, I think the idea of you making API requests using your users'
credentials is a bad one from the start. If the third party in question wants
to allow requests-on-behalf-of, they should provide a proper API for it; if
not, you shouldn't be working against their wishes by impersonating your
users.

That said, if you really really have to do this: Have your users provide you
with their username and password; generate a random symmetric encryption key;
store (username, encrypted password) on your systems and send (username,
encryption key) to the user as a cookie.

This will give you safety against an attacker who can steal your database or
the user's cookies; it won't give you any protection against an attacker who
can steal both of those (that would impossible), nor will it give you any
protection against an attacker who controls your server at a time when a user
tries to use your service (again, that would be impossible).

But I still think this is a really bad idea.

~~~
jrockway
_First, I think the idea of you making API requests using your users'
credentials is a bad one from the start. If the third party in question wants
to allow requests-on-behalf-of, they should provide a proper API for it; if
not, you shouldn't be working against their wishes by impersonating your
users._

This is true, but unfortunately we live in the real world, and hacks are
sometimes necessary. Look at Mint.com, for example. Give some site all your
banking details? WHOA THERE. But it turns out the service is very useful, and
it works with pretty much every bank. If they had waited for proper APIs to
exist, someone else would have beaten them to market.

------
simonw
If you can convince the third party site to adopt OAuth, do that.

Otherwise, one technique you could use is to encrypt their password using a
key derived from a hash of the password they enter. When they log in, set that
hash as their cookie. Each time you need to use the third party password, read
that cookie and use it to decrypt the stored password.

Since you don't know their real password for your own app (as you only store a
different hash of it), you won't be able to derive the hash used for the
decryption process (note that this means you need to store a hash of their
password for your own authentication using a different salt from the one you
use to protect their encryption).

With this technique, having access to your database is not enough to decrypt
their third-party password.

Unfortunately none of this resolves the root problem. Firstly, by asking users
to trust you with their passwords for other sites you are teaching them to be
phished. Secondly, if you turn evil (or someone evil acquires your site in
some way) the server-side logic can be changed to steal the user's password.

~~~
tptacek
Don't do this: do what Colin said. Let k be 32 random bytes (using your OS's
_secure random number generator_ ), store AES-256-CBC(k, [user, pass]), send k
in a cookie over HTTPS with the "secure" flag set (that "k" is password-
equivalent, and can't leak over an HTTP connection).

Repeating Colin's caveat: the fact that you had to type "A-E-S" into your code
to make the scheme work is strong evidence that you are doing something bad.

------
Herring
Store it encrypted on their computer then decrypt it each time it's sent to
you? Maybe I'm missing the problem.

One way or another you're going to have to hold it as plaintext to submit it
to the other site. It's nice to hold it only in RAM, but the vulnerability is
always there.

~~~
bbb
Exactly, and use public key crypto:

1) Generate public/private key pair for user.

2) Send public key to client.

3) Encrypt PW on client, store as cookie.

4) Store (user, private key) on your server.

5) Client now sends the encrypted PW whenever it is needed.

6) Server decrypts on demand, but does not store a local copy.

Since you never relinquish the private key this is pretty much unbreakable for
spyware going through a client's cookies. (Nevermind key loggers...)

