docs(auth): what the third reading found, and Proton's rule (ADR 0017)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
This commit is contained in:
parent
ad52da5a94
commit
1ada2e27f6
1 changed files with 103 additions and 34 deletions
|
|
@ -338,6 +338,57 @@ these; all but the ninth were fixed (the developer's choice):
|
|||
unavailable**, which the app read as "no password sign-in here": it has its own
|
||||
refusal now (`passwordChanged`), saying to sign in again with the new password.
|
||||
|
||||
### Third reading (21 Oct 2026)
|
||||
|
||||
A third independent reading, of the re-reading's fixes (`1383640..a45842f`), found its
|
||||
items 1, 2, 4, 6, 7 and 10 fixed and 5 and 8 holding but for the points below. The first
|
||||
finding was a regression of item 3, so rather than count once more, the developer chose
|
||||
Proton's rule (21 Oct 2026):
|
||||
|
||||
- **A session alone never gets a code checked.** Every signed-in change of how an
|
||||
account is secured takes the owner's proof (`OwnerProof`): the password's SRP proof
|
||||
for a change's challenge (`password.beginChange`, the person checked) and then a TOTP
|
||||
or recovery code. That is adding an authenticator once one is confirmed, removing a
|
||||
confirmed one, new recovery codes, a new phrase, a new password and deleting. Only the
|
||||
first authenticator (none confirmed, after a reset carried out too) is confirmed with
|
||||
its own code alone, and removing one never confirmed takes nothing. A proof given where
|
||||
none is taken is refused, and a confirmed authenticator's code is never checked again
|
||||
for a session (confirming it again is refused as unknown), so no success passes a
|
||||
proof unchecked. `wrongExistingCode` goes: a wrong code from another authenticator is
|
||||
a wrong proof.
|
||||
- **A session's proofs count for it alone** (`asOwnerProofTry`, table
|
||||
`session_code_failures`, where the session is, on a member too): each counted before
|
||||
it is checked, cleared only by one accepted, the tenth wrong in a row ending the
|
||||
session. They never count toward the account's waits nor wait for them, and a new
|
||||
password forgets those waits.
|
||||
|
||||
The findings, and what was done:
|
||||
|
||||
1. **A stolen session guessed codes without end** (high): nine wrong codes for new
|
||||
recovery codes, then removing an unconfirmed authenticator of its own, a success that
|
||||
cleared the count, and again. Closed by the rule: no code is checked for a session
|
||||
without the password first, and only a proof accepted clears the count.
|
||||
2. **Whoever knew the password held a signed-in owner out of changing it**: ten wrong
|
||||
codes at sign-in made the account's codes wait, and the owner's change waited too.
|
||||
Signed-in proofs no longer wait for the account's waits, and the change forgets them.
|
||||
3. **A stolen session spent the ten changes an account begins an hour**, holding its
|
||||
owner out of changing the password, a new phrase and deleting. Beginning counts
|
||||
nothing against the account: at most 30 an hour per session, a bound on the work one
|
||||
session asks for that holds back no other; only failed proofs count, per session.
|
||||
4. **Deleting, with the authenticators' reset taken effect but not carried out**, was
|
||||
offered a code field (the app read "an authenticator was confirmed") which the
|
||||
instance refused (it read "no second factor works"). The instance takes a TOTP or
|
||||
recovery code wherever an authenticator is confirmed, a code by mail where no second
|
||||
factor works, and tells the app which (`SignInWays.secondFactorWorks`).
|
||||
5. **A device that didn't know the account's address couldn't change the password, set a
|
||||
new phrase or delete** (`addressUnknown`). Signed-in calls take no address any more:
|
||||
nothing there mails, the account's waits being the sign-in's. Deleting by mail asks
|
||||
for the address where the device doesn't know it, as the code goes there; the
|
||||
instance takes the code only for the account's own address.
|
||||
6. **The code mail's subject hid its purpose**, which a notification shows alone. The
|
||||
subject names it ("K7QX-M2PD: your Halkyon Learn code to delete your account"), and the
|
||||
sign-up mail says it also gives a password to an account with that address and none.
|
||||
|
||||
## Consequences
|
||||
|
||||
- People keep a password, an authenticator app and a recovery phrase: more to keep than a
|
||||
|
|
|
|||
Loading…
Reference in a new issue