hivewallet / discussions

Discussions and issues related to Hive
https://github.com/hivewallet/discussions/issues
3 stars 2 forks source link

Hive Web Wallet Authentication & Security #8

Open weilu opened 10 years ago

weilu commented 10 years ago

Assumptions

  1. User needs to conveniently & securely access his/her wallet on mobile
  2. Client code is vulnerable to modifications with malicious intent. It can potentially be modified on the client side, by browser plugins (e.g. chrome extensions that send seed to a foreign server) and user themselves (e.g. to pry on other users' information).
  3. Server may be compromised, in which case users' funds still need to remain secure.

    Client code distribution

Client code (i.e. html, javascript, css) should be versioned, bundled and signed with a private key that we keep offline. The corresponding public key should be bundled with the distribution. The subsequent times when a user visits w.hivewallet.com, the client first checks the version of client bundle on server, if it is the same as it's own version there's nothing to do. If there is a newer version on server, the client uses the public key to verify the fingerprint of the newer version. If it matches, downloads and replaces itself. If not, it assumes that the server is compromised and does nothing. This partially addresses Assumption #3.

I'm not sure how exactly this can be implemented yet or if it is possible at all in the browser.

Before using hive web wallet

Disable all browser extensions on *.hivewallet.com. Chrome: Extension Automation. This partially addresses Assumption #2.

New wallet (Sign up)

  1. Client side scripts generate a seed phrase, have the user write down the seed phrase.
  2. Prompt user to set a pin. The scripts generate a wallet ID by hashing the seed using SHA-512 [1]. The pin and the wallet id are posted to server over https.
  3. Server checks if the wallet id already exists in the user database, if it does, proceed with the login process. Otherwise server randomly generates a long password(as long as the seed). Then creates a new user in the database with user id being the wallet id, password being the pin[2], and long_pass being the generated long password.
  4. Sever sends the long password back to the client.
  5. The client encrypt the seed with the long password, stores the wallet id and encrypted seed in browser local storage.

    Existing wallet (Sign in)

    With pin

  6. User enters pin. Client scripts send wallet id and pin to server
  7. Server verifies the pin against hash. If it's correct go to 3, otherwise go to 4
  8. Server returns the long password that corresponds to the wallet id. Client opens the wallet. Client auth directly with CouchDB with wallet id and pin for user info read/write on subsequent requests [3].
  9. If the pin is incorrect, server increments failed attempt counter. If counter >= 5, delete the user doc(containing the long password, wallet id and counter) from the users database. Then send client a response to erase local encrypted seed. From there, the client is only able to open a wallet with the original seed phrase. Note that the user info is stored in a separate database therefore remains available to user successfully authenticated as the user with the wallet id.

Note: an existing wallet is accessible with pin only after it has been accessed once from the same browser using seed phrase. Allowing accessing with pin using the process described above addresses Assumption #1.

With seed phrase

  1. User enters the seed phrase.
  2. New wallet step 2-6

    Notes on technical details

    • [1] There is a chance for hash collision, but it is extremely small. http://permabit.wordpress.com/2008/07/18/what-do-hash-collisions-really-mean/
    • [2] CouchDB 1.2 onwards will see the password field in the document and automatically create a password salt and hash the password for you
    • [3] To simply the synchronization between client side database(PouchDB) and the server side database (CouchDB), we use basic auth (e.g. https://alice:secret@hive.cloudant.com) for reading/updating/synchronizing. We need to set up validation functions & permissions for read/write on per doc basis. This also partially addresses Assumption #2
    • Server has no knowledge of the seed phrase in any form
    • Server stores user information like name, email, currency preference, contacts etc. so that user has a consistent experience when switching browsers/devices
    • We will encrypt user information (with the wallet seed) as much as possible, but certain information needs to be readable by the server for contact management, for example contacts & addresses belong to each wallet id. In case when the server is compromised, that information would be known to the world.
javgh commented 10 years ago

Looks good to me!

Regarding browser extensions: I would hope that browser extensions are mostly sandboxed from each other (maybe even to the degree, that websites in different tabs are sandboxed from each other?) and would therefore think that disabling other extensions shouldn't be necessary. Or did you look into it more and saw specific ways in which extensions could modify each other?

And one idea I had, which might be a bit controversial: I was wondering if it could be worthwhile to sacrifice a few bits of entropy from the seed phrase for a better UX when returning to a wallet. Specifically: We might save the first and last word of the seed phrase (maybe already too much?) unencrypted and only encrypt the middle part. When the user returns, you could then show something like this:

    walnut ???? ???? ???? ???? ???? ???? ???? ???? ???? ???? juice     [Enter PIN to unlock]

Indicating to the user, that he is returning to an existing wallet and making it clear, that it is the one he expects, by showing part of his seed phrase.

When I was running Instawallet, I noticed that many users did not really understand how cookies work. I got the impression, that the mental model of most users is, that if they haven't told the website anything (e.g. an email address), the website doesn't know who they are. So the fact that the website could remember them with a hidden cookie in the background was often confusing to them (I eventually removed cookies from Instawallet - you then always needed the link). That's why I'm thinking, that if we are going to remember the seed phrase in a cookie, we should do something to lessen the surprise/confusion that results from that, which might be a hint using the first and last word like described above.

weilu commented 10 years ago

Chrome extension has a permission level which allows "access to your data on all websites". I imagine an extension like 1password which needs to be able to auto-fill login forms have such permission. In our case we don't want any extension to read the seed phrase or the pin, so I thought better disable them all on *.hivewallet.com.

That first + last word hint idea does sound like an UX improvement. But I'm afraid it's not possible with the current design. Currently the browser only store the seed that is encrypted by the random long password provided by the server. The long password is not sent until user enters the short pin correctly. So until then we can't reconstruct the seed phrase.

Would it be sufficient to show just the pin input box for returning users, and show options to enter seed phrase or create new wallet for new users?

ghost commented 10 years ago

I like Jan's idea about the entropy sacrifice -- like chromosomal telomeres for seed phrases -- but on the other hand, couldn't we just make it 14 words?

weilu commented 10 years ago

Because we want our wallet to be compatible with other HD wallets?

javgh commented 10 years ago

Good point regarding extensions that can access data on all websites - that might indeed be an attack vector!

I was also wondering, whether a 14 word seed phrase would break compatibility with other wallets. But reading BIP39 again, it seems we could just go to 15 word sentences and other BIP39-compatible wallets should handle it just fine.

weilu commented 10 years ago

@javgh yes you are right. We can go up to 15 words(but not 14 words) and still be compatible. Can @haustraliaer @jenbennings @mattatgit confirm the workflow before I go ahead and change it?

mattatgit commented 10 years ago

@weilu i'm not sure we can really give you a definite answer, Wei. It's a bit like designing a moving train. We haven't got enough progress on the login flow to be able to say one way or the other yet. Sorry we can't help you more just yet.

javgh commented 10 years ago

Regarding hiding the seed phrase: I would opt for being able to look up the seed phrase later, but always require the PIN to be entered for that again. So even if you are already logged in, revealing the seed phrase would ask for your PIN again.

mackuba commented 10 years ago

I'm not sure how exactly this can be implemented yet or if it is possible at all in the browser.

I guess it could be done with Application Cache, though I haven't used it myself, and I've heard it isn't very flexible...

Disable all browser extensions on *.hivewallet.com. Chrome: Extension Automation.

Good luck getting users to do that ;) Also, can this be set globally, so that it includes all extensions, even those installed later?

Regarding hiding the seed phrase: I would opt for being able to look up the seed phrase later, but always require the PIN to be entered for that again. So even if you are already logged in, revealing the seed phrase would ask for your PIN again.

+1

In general: I like the whole process as described by @weilu, seems like she thought about everything. I was thinking at first that the wallet would have almost no server components to avoid centralization, but I guess if we can offer more convenience without sacrificing any security (or actually improving it this way), then there's nothing bad with having a server-side part.

ghost commented 10 years ago

"I was thinking at first that the wallet would have almost no server components to avoid centralization, but I guess if we can offer more convenience without sacrificing any security (or actually improving it this way), then there's nothing bad with having a server-side part."

...Though it should be expressly avoided where possible. If "Hive" the org is ever gone, I don't want these apps to be unusable.

weilu commented 10 years ago

@jsuder Application Cache looks interesting, though I don't think by itself it's enough to serve our verification goal. We almost need something like a client container (served from a different server) which verifies, decompresses & executes the packaged code bundle.

Though it should be expressly avoided where possible. If "Hive" the org is ever gone, I don't want these apps to be unusable.

People can run their own servers. I consider browsers extremely insecure environments. If we want to provide a good user experience (e.g. pin access) without compromising security, using a server is a straightforward solution.

I'm also considering using stuff from https://unhosted.org. But 1) current pin auth workflow needs to be re-designed. Based on my understanding, if data goes directly from user specified database to the browser, there's no way we can put logic between them, which means the "pin + long password" auth design wouldn't work. 2) I don't know if it'll make contact management impossible.

weilu commented 10 years ago

This is interesting: https://unhosted.org/adventures/13/Dealing-with-users-in-unhosted-web-apps.html. It actually simplifies contact management if it works as described :)

tgerring commented 10 years ago

Interesting link @weilu!