-
Notifications
You must be signed in to change notification settings - Fork 96
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
multi: add support for password recovery using seed #2477
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Cool! I left some considerations (mostly from user perspective).
Several more comments on Forgot App password
form:
- ideally, it should be as close as possible (in terminology, layout, etc.) to
Change App password
(including variable names in the code); additionally I noticed that in UI some buttons/views use "Application" while other buttons/views use "App" (and some forms don't even mention either), would be better to use one of those everywhere for consistency - the name and description on
Forgot App password
form could emphasize that it's a password reset and not initial setup, which it currently sounds like:Set your app password. This password will protect your DEX account keys and connected wallets.
- description on
Forgot App password
form could mention that wallet data will be erased and that user will need to re-create all wallets - I'd remove
Remember my password
flag fromForgot App password
form for simplicity (it's already overloaded with info), it's non-critical functionality and it isn't clear that Submit will log you in right away; alternatively we could just redirect user to login page (but that's suboptimal since he'll need to enter password once again)
client/webserver/locales/en-us.go
Outdated
"Reset App Password": "Reset App Password", | ||
"Forgot App Password": "Forgot App Password", | ||
"Download Application Seed": "Download Application Seed", | ||
"seed_restore_warning": "Make sure to use the correct seed for this application. Using the wrong seed will result in loss of funds.", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is a better way than displaying this warning, I think, it'll also address this concern you have:
There might be some security concerns as any "valid" 128-char hex string can be used as a seed and there's no way to verify the reset pass seed except that wallets created with it will be different.
Upon seed generation (and for existing seeds, we can do that upon login once, to preserve backward compatibility) we can hash seed and store that hash in plain text on disk.
We can remove this warning tooltip and instead just hash the seed user supplied and compare it against that "original hash" we have stored on disk. If they match - it means user entered correct seed (the one he was using DEX with in the past), if they don't match we should warn the user suggesting:
- either to check and re-enter his seed again
- or use a different flow to hard-reset his DEX app entirely (this use-case is also a separate valid one, say if I downloaded DEX to just try it out, but didn't back up the seed and forgot the password I used ... I have no way to reset it, unless I delete DB manually)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can remove this warning tooltip and instead just hash the seed user supplied and compare it against that "original hash" we have stored on disk. If they match - it means user entered correct seed (the one he was using DEX with in the past), if they don't match we should warn the user suggesting:
In eb467a4, I opted to stick to our existing encryption pattern which requires a password to create a "crypter" and storing the necessary details to DB.
use a different flow to hard-reset his DEX app entirely (this use-case is also a separate valid one, say if I downloaded DEX to just try it out, but didn't back up the seed and forgot the password I used ... I have no way to reset it, unless I delete DB manually)
I think in this scenario they will have to do the 'advanced stuff'. We could have a guide in place for this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In eb467a4, I opted to stick to our existing encryption pattern which requires a password to create a "crypter" and storing the necessary details to DB.
Your approach is even better!` perhaps I didn't quite understand how the seed encryption-decryption works,
I think in this scenario they will have to do the 'advanced stuff'. We could have a guide in place for this.
In general, users don't read tutorials/text, not anymore (when they have a lot of apps that do stuff for them), so I'd treat a tutorial as a measure of last resort and I frankly think things like #2468 is mostly a waste of time (might be useful for a couple of nerds, but that's it). I mean, it's nice to have tech spec/article but to force your users read it before using an app ... is where you lose them.
Perhaps me advocating this topic is also a waste of time, I'll stop now.
That said, this scenario of DEX re-creation is probably a rare one - hence doesn't deserve much attention any time soon (perhaps could be a separate issue lying around for someone, perhaps new contributor to the repo, to pick up down the line).
[ID_INVALID_SEED]: 'Invalid seed', | ||
[ID_EXPORT_SEED_DOWNLOAD]: 'Enter your app password to download your seed. Make sure the downloaded file is saved in a secure folder.', | ||
[ID_EXPORT_SEED_VIEW]: 'Enter your app password to view your seed. Make sure nobody else can see your screen.', | ||
[ID_DOWNLOAD]: 'Download', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reading downloading/uploading seed as file - it isn't something I personally would ever use, and it kinda promotes bad practice of storing uncyphered/unencrypted seed on your PC, or am I missing something ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it kinda promotes bad practice of storing uncyphered/unencrypted seed on your PC
I agree. I was playing with the thought that downloading would be better than copying them(we currently don't restrict this). Manually writing out the seed hex can be a pita considering that they are not valid words even as they appear in chunks.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was playing with the thought that downloading would be better than copying them(we currently don't restrict this).
I think @martonp implemented some kind of warning for using clipboard when dealing with private key for Ethereum, perhaps we can add similar warning for seed. But, "proper solution", as per your comment
Manually writing out the seed hex can be a pita considering that they are not valid words even as they appear in chunks.
would be to move to 12/24 word seed phrase, I have no idea why it hasn't been done yet.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for your input. I think these suggestions can go into an issue page for better attention.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, this one's a pita because we have 64-bit seeds. Solution is needed. Keep clipboard available for now. OK to add a warning.
Once everything is ready, we might want to test how this reset-app-with-seed feature works when we have some open/executing orders (to see 1) whether it allows seed reset - which it should and 2) whether wallet re-sync from scratch will allow for re-discovering and completing outstanding trades - both for redeem and refund), just leaving this note here as a reminder. |
Thanks for the review @norwnd, I'll convert this to draft until it's ready. |
It's standard practice to log in again after a password reset to ensure the new password (If we don't want the auto login). |
I have not tested this yet but I thought you would have to recreate all internal wallets and Reconfigure all external wallets? The passwords for those is encrypted and based on the user's password initially? I really think you should have waited for buck or chap to comment on the issue, this is a lot of work and not a bug fix. |
Thanks for your input @JoeGruffins. I have a tested POC that follows the same part as password change and won't require recreating or reconfiguring wallets. I'd appreciate more suggestions on this. |
723034e
to
eb467a4
Compare
Yes, it is and since it's minor I've included a fix for it here. @buck54321, do you want me to PR the fix separately? |
With the new suggestion, I think these issues won’t be a concern anymore. |
No. It's fine here. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I liked @norwnd's original suggestion to use a hash of the seed. Please consider buck54321/dcrdex@dbeaf39...buck54321:dcrdex:simpler-seed-hash.
edit: Nevermind. Is bad suggestion.
@buck54321 I may be wrong but your diff replaces the inner key and so for any current wallets we will not be able to decrypt their passwords any longer? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure if it's a pre-existing issue, but if I go to the settings page when I'm logged in and refresh the page, only the settings option will be displayed in the drop down menu. (This is after I changed .UserInfo.Initialized
to IsInitialized
in settings.tmpl).
Personally I would like auto-login, but I'm just lazy :).
Also, @JoeGruffins is right about the encrypted db passwords. I think it's just as secure to encrypt the password with the seed as storing the hash anyways.
Ooooh. Right. |
Thanks for testing @martonp. I'll look into this. |
@buck54321 thanks for reviewing. I'll make changes soon. |
I think this was fixed by #2481 |
291aec2
to
a891bc1
Compare
I don't think we should add this functionality if it requires messing with our existing security. |
Do you think this approach is reasonable instead? pass protects seed (we have this already) |
@ukane-philemon What do you think about this upgrade buck54321/dcrdex@024aa50...buck54321:dcrdex:seed-derived-inner-key ? |
Thanks. Your suggestion will allow users to recover with their seed without the additional encryption and recovery seed in this PR. |
6e7127e
to
8e39549
Compare
Rebased. |
3d6d757
to
6b0531c
Compare
Per brief conversation with wizards @jrick and @davecgh, I think we should append some constant domain bytes to the seed before hashing into the innerKey := blake256.Sum256(seed) we would do something like const keyParameter = []byte{0xaa, 0xbb, 0xcc}
innerKey := blake256.Sum256(append(seed, keyParameter)) But write a function for it func seedKey(seed []byte) []byte { .. } since it's used in multiple places |
I would suggest using the result of hashing a known value that clearly describes its purpose so that it is a publicly verifiable value that is clear exactly where it came from and that it is a nothing-up-my-sleeve number as opposed to a potential attempt to insert a backdoor. Something like the following: func seedKey(seed []byte) []byte {
// keyParam is a domain-specific value to ensure the resulting key is unique
// for the specific use case of deriving an inner encryption key from the
// seed. Any other uses of derivation from the seed should similarly create
// their own domain-specific value to ensure uniqueness.
//
// It is equal to BLAKE-256([]byte("DCRDEX-InnerKey-v0")).
keyParam := [32]byte{
0x75, 0x25, 0xb1, 0xb6, 0x53, 0x33, 0x9e, 0x33,
0xbe, 0x11, 0x61, 0x45, 0x1a, 0x88, 0x6f, 0x37,
0xe7, 0x74, 0xdf, 0xca, 0xb4, 0x8a, 0xee, 0x0e,
0x7c, 0x84, 0x60, 0x01, 0xed, 0xe5, 0xf6, 0x97,
}
key := make([]byte, len(seed)+len(keyParam))
copy(key, seed)
copy(key[len(seed):], keyParam[:])
innerKey := blake256.Sum256(key)
return innerKey[:]
} |
c872659
to
201bde4
Compare
Thanks for the suggestion @buck54321, @davecgh. I used your suggestion as is after verifying with....
|
- Add /resetapppassword endpoint. - Add ResetAppPass(...) to core.Core. - Fix navigation menu display after logout - Fix bug that prevents showing error on Export App Seed form - Modify Login Form and add new button to settings page to accomodate new password reset funtionality. - Hide unecessary/unused btns on the settings page if user is logged out. - Add new form for App Pass Reset. Signed-off-by: Philemon Ukane <[email protected]>
Signed-off-by: Philemon Ukane <[email protected]>
Signed-off-by: Philemon Ukane <[email protected]>
Signed-off-by: Philemon Ukane <[email protected]>
Signed-off-by: Philemon Ukane <[email protected]>
Signed-off-by: Philemon Ukane <[email protected]>
Signed-off-by: Philemon Ukane <[email protected]>
Signed-off-by: Philemon Ukane <[email protected]>
Signed-off-by: Philemon Ukane <[email protected]>
201bde4
to
952fcb1
Compare
Closes #2475.
Changes in this PR:
/resetapppassword
)new password reset functionality.
Restore Seed
label on the 'init' page.Implementation details:
I figured out we needed a way to verify that the provided seed was indeed the correct seed, so I opted to use part of the original seed to encrypt seed+pass. A user wanting to reset pass will just provide the exported seed, we derive the encryption password from it and get the original seed and password with which we can change to the new password.
This is a tested and working POC as in the video below and suggestions are welcomed.
PS: There's also a
Reset App Password
(apart from theforgot app pass
btn) on the settings page that also opens the rest pass form, but I guess we'll have to keep only one?UI changes and password reset flow(video):
https://github.com/decred/dcrdex/assets/57448127/92f31aee-0fe3-4de4-b525-99eecb5d7632
After logging out (before):
After logging out (now):