update security analysis, two-pw/pairing extensions
Родитель
0ca39593b9
Коммит
db1ea82f96
|
@ -314,7 +314,7 @@ There is no MAC on wrap(kB). If the keyserver chooses to deliver a bogus wrap(kB
|
|||
HAWK provides one thing: integrity/authentication for the request contents (URL, method, and optionally the body). It does not provide confidentiality of the request, or integrity of the response, or confidentiality of the response.
|
||||
For /certificate/sign, we do not need request confidentiality or response confidentiality, since the client's pubkey and the resulting certificate will both be exposed over a similar SSL connection to the storage server later. And it is sufficient to rely on the response integrity provided by SSL, since the client can verify the returned certificate for itself. For the other keyserver APIs protected by HAWK, these properties are either unnecessary, or are provided by additional mechanisms.
|
||||
|
||||
# Analysis
|
||||
# Security Analysis
|
||||
|
||||
This protocol aims to have two main security properties:
|
||||
|
||||
|
@ -325,13 +325,66 @@ This is weaker than the earlier SRP-based protocol, but still stronger than comm
|
|||
|
||||
As with the SRP-based protocol, if the client is implemented in web content, then a strong active attacker (who can MitM TLS connections and thus serve doctored client code) can bypass the entire protocol and learn the password directly.
|
||||
|
||||
# two-password extension
|
||||
The long-term server data is intended to be safe against "easy" dictionary attacks, meaning that given everything stored in the DB, a passive attacker must still perform the full scrypt stretch to test each password guess.
|
||||
|
||||
In V2, we plan to add an optional second password with improved security. The general idea is to use the original SRP protocol, with the second password as input (not using the first password), to produce kB. The API to perform SRP will be gated by the sessionToken, as will use of the scrypt-helper, which could marginally improve our DoS story.
|
||||
The passive attacker gets access to two values that serve as password-guessing oracles. The first is "verifyHash", which is derived from the output of the full scrypt-based stretch. The second is `wrap(wrap(kB))` (which could be used in conjunction with some class-B encrypted data to test passwords), which is also protected by the scrypt step: for each password, the attacker runs the full computation to derive kB, then tries to decrypt some data and sees if its HMAC check passes.
|
||||
|
||||
If an account is configured for a second password, the `/account/login?keys=true` request will return a field to that effect, instead of a keyFetchToken. Changing from one password to two, or vice versa, will involve extra API calls.
|
||||
The stored pre-encrypted response to `GET /account/keys` would also serve as an oracle, but the server explicitly doesn't retain the `keyFetchToken` that encrypts it. Since keyFetchToken is randomly generated and independent of the user's password, the data it encrypts does not help test password guesses.
|
||||
|
||||
Use of a second password will restore all the security properties of the original protocol: only the scrypt-helper gets the "easy" brute-force attack, and the only "hard" brute-force attacks are available to a malicious active server or a TLS-level eavesdropper on the create-account and forgot-password flows. kA is protected from all eavesdroppers.
|
||||
## vs. old-Sync
|
||||
|
||||
Given the Sync legacy of full-strength random keys, exchanged with J-PAKE pairing, we'd like to make it possible to achieve similar levels of security with the new protocol. When viewed from the perspective of old-Sync, this new protocol has the following weaknesses:
|
||||
|
||||
* Passwords. All security, even against (rate-limited) online attacks, is limited by the strength of the user's password. old-Sync (nominally) had no passwords, and no practical amount of guessing would yield the account's encryption key. Moderate-strength passwords can benefit from expensive stretching, but users with a password of "123456" will probably lose control of their account no matter what we do.
|
||||
* Weak client-side stretching: the server (or someone who successfully compromises it), or an attacker who can forge TLS certificates (or who records traffic and later learns the server's TLS private key), both get enough information to perform a dictionary attack that is only limited by the weak PBKDF-based stretch. This is relatively cheap.
|
||||
* Use of Password in a Web Context: when the client of this protocol runs inside a web page, rather than in browser chrome, a new set of attacks become possible. Compromised/coerced servers can quietly deliver modified pages which reveal the user's password to a waiting attacker. This becomes more likely as the scope of Firefox Accounts grows to include new use cases which preclude a chrome-only client (e.g. signing into Marketplace from other web browsers). This same problem exists with corrupted browser updates, of course, but it is nominally possible to download a browser from a trusted source and disable automatic updates, whereas it is not feasible to prevent or even detect surreptitious web-page tampering.
|
||||
|
||||
These weaknesses are the result of compromises. The features obtained in this bargain are:
|
||||
|
||||
* recover account data (with the password) after losing your only device
|
||||
* add a new device without access to an old device
|
||||
* use slow/old clients (rather than doing expensive scrypt stretching client-side)
|
||||
* generalized Firefox Accounts, with more features than just Sync
|
||||
|
||||
## vs. earlier SRP-based protocol
|
||||
|
||||
Relative to the SRP-based protocol described in https://wiki.mozilla.org/Identity/AttachedServices/KeyServerProtocol , this "onepw" protocol has the following weaknesses:
|
||||
|
||||
* a TLS-level eavesdropper learns authPW (allowing them to control the account), learns kA (revealing all class-A data), and learns wrap(kB) ("easy" brute-force attack)
|
||||
* the auth server gets an "easy" brute-force attack (by knowing authPW or wrap(kB))
|
||||
|
||||
In exchange for these weaknesses, this protocol gains the following advantages:
|
||||
|
||||
* simpler client: no SRP necessary
|
||||
* faster client: less client-side stretching
|
||||
* server can upgrade protection of stored data (e.g. do more stretching) with minimal client involvement
|
||||
|
||||
# Extensions
|
||||
|
||||
## Changing Server-Side Protections
|
||||
|
||||
If we need to change the scrypt stretching parameters (or move to some other algorithm entirely), the server can do this any time the user logs in or otherwise presents `authPW`. The server should store some version marker in the database with each account row, to perform the same stretching each time, but can use different values for different accounts. The requirements are that the server can 1: compare `authPW` against an earlier value, 2: return the same `wrap(kB)` as was submitted earlier, and 3: provides adequate protection against database compromise.
|
||||
|
||||
Likely changes include:
|
||||
|
||||
* store verifyHash and `wrap(wrap(kB))` in encrypted form, protected by an HSM, or with a key that is manually typed into the server instead of being stored on disk
|
||||
* adding two-factor (2FA) verifiers to the database
|
||||
|
||||
## two-password extension
|
||||
|
||||
One proposal to address the "Use of Password in a Web Context" weakness above is to introduce an optional second password, with improved security. The general idea is to feed the second password into the original SRP protocol (client-side scrypt, SRP-protected exchange of strong wrapped kB). The second password would only be used for Sync (not for plain Firefox Account login), and only entered into chrome UI (never into web content).
|
||||
|
||||
The API to perform SRP will be gated by the sessionToken, as will use of the scrypt-helper, which could marginally improve our DoS story.
|
||||
|
||||
If we implement this, it will require a `/v2` API call to use. When an account is configured for a second password, the `/v2/account/login?keys=true` request will return an error or a field to that effect, instead of a keyFetchToken. Changing from one password to two, or vice versa, will involve extra API calls. Using the first-generation `/v1` API on such an account will return an error that says you must use a newer client.
|
||||
|
||||
Use of a second password will restore all the security properties of the earlier SRP-based protocol: only the scrypt-helper gets the "easy" brute-force attack, and the only "hard" brute-force attacks are available to a malicious active server or a TLS-level eavesdropper on the create-account and forgot-password flows. kA is protected from all eavesdroppers.
|
||||
|
||||
## pairing extension
|
||||
|
||||
An even stronger improvement would be to re-introduce an optional pairing flow. When this is enabled for the first time, the client will produce a strong random key and include it in the derivation of unwrapBkey. The server will make a note of the fact that pairing is enabled. When connecting later devices, the client will see this flag and initiate the J-PAKE pairing UI to transfer the additional key.
|
||||
|
||||
This pairing flow can be better than the old-Sync flow because we have more information to work with. Depending upon how much the user types before we start the transfer, we may know an email address (reducing the number of candidate machines to talk to), and the account password (making it harder to for the attacker to participate in the pairing process). This will allow us to automatically pop up the pairing dialog on the sending machine, and to reduce the length of the sync code considerably (perhaps just a 4-digit PIN).
|
||||
|
||||
# delta from old SRP protocol
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче