|
| 1 | +## Problem |
| 2 | +Synchronizing a user session between stacker.news and a user-owned custom domain, means giving up the whole JWT, which can be stolen and replayed. |
| 3 | + |
| 4 | +For example, in a scenario like DNS hijacking, the malicious user that owns the custom domain can point their DNS record to a server of their own, **log** the incoming requests, **collect** the JWTs and **replay** them. |
| 5 | + |
| 6 | +Usually, mitigations are used for this kind of problem: |
| 7 | +- fingerprinting |
| 8 | +- dns polling |
| 9 | +- short-lived sessions, with refresh tokens |
| 10 | +- aggressive checks on custom domains |
| 11 | + |
| 12 | +I think that some mitigations are correct, such as **dns polling** to take measures against the malicious owner; others might be too much. |
| 13 | + |
| 14 | +## Per-device keys |
| 15 | +**The case for per-device ECDH Key Pairs** |
| 16 | + |
| 17 | +As a form of authentication, we can use ECDH shared secrets to either |
| 18 | +- sign requests for the GraphQL endpoint |
| 19 | +- encrypt JWT payloads |
| 20 | +To accomplish this, each device will have its own ECDH key pair, generated and stored in IndexedDB on first visit. |
| 21 | +It can also be used in the future for encrypted messaging |
| 22 | + |
| 23 | +An example flow can be: |
| 24 | +``` |
| 25 | +
|
| 26 | +1. Device generates key pair |
| 27 | +2. On login, server creates an ECDH key pair |
| 28 | +3. Client and server exchanges public keys |
| 29 | +4. Server and device derives the same shared secret with each other |
| 30 | +-- Stores: |
| 31 | + user, server_priv_key, client_pub_key, shared_secret_hash |
| 32 | +5. Server issues an encrypted JWT using the shared secret |
| 33 | +6. Device decrypts JWT with the same shared secret |
| 34 | +``` |
| 35 | + |
| 36 | +Shared secret rotation is part of best practices in this context. |
| 37 | + |
| 38 | +**The case for ECDSA** |
| 39 | + |
| 40 | +ECDSA, much like the ECDH route above, can be used to generate a key pair on the first visit and share its public key with the server, to bind it to the user we're importing from `stacker.news`. |
| 41 | + |
| 42 | +ECDSA can be used to sign every request or JWTs, the server will then verify the signature and accept the request if the signature is valid. |
| 43 | + |
| 44 | +An example flow can be: |
| 45 | +``` |
| 46 | +1. Device generates key pair |
| 47 | +2. Public key is sent to server and bound to a user |
| 48 | +3. Server issues a JWT that includes the public key fingerprint |
| 49 | +4. On each requests, client signs a message with private key |
| 50 | +5. Server verifies the JWT and the signature, proving possession |
| 51 | +``` |
| 52 | + |
| 53 | +If the JWT gets stolen, it's useless without the device private key. |
| 54 | + |
| 55 | +###### Bonus |
| 56 | +A bonus point of using key pairs, is the capability of tracking devices connected to an account, enabling session revocation. |
0 commit comments