NOTE
Designing User Registration and Login
A historical note on login state, username/password registration and login, verification codes, and third-party login.
This is a historical learning note and may contain outdated or incomplete understanding.
1. What Is Login State?
After login, the system returns a credential that identifies the user in subsequent requests. Different scenarios may use credentials with different scopes and lifetimes. Concrete ticket types, names, privilege relationships, and expiration rules are implementation details, so only the abstract concept is retained here.
2. Username + Password
2.1. Security Requirements
First, make it difficult for the database to be leaked. Even if the database is leaked, an attacker should not be able to recover users’ passwords from it. Even if the database is leaked, an attacker should not be able to forge a login request that passes verification. Even if the database is leaked and an attacker hijacks a user’s request data, the attacker should not be able to recover the user’s password.
2.2. Registration Flow
- The user enters the plaintext password.
password = 123456
- The client performs a normal hash on the password.
client_hash = MD5(password) // e10adc3949ba59abbe56e057f20f883e- If an attacker intercepts the request, the plaintext password could otherwise be known, so this step avoids transmitting the plaintext password.
- The client adds a fixed salt to the result of step 2 and performs a slow hash.
client_hash = BCrypt(MD5(password) + salt) // MFfTW3uNI4eqhwDkG7HP9p2mzEUu/r2- The purpose of adding a salt is that if
passwordis short, the password may be inferred. After adding a salt and hashing again, it becomes much harder to infer. - Even if reverse inference is not possible, the password can be found by forward brute force using a rainbow table. Therefore
BCryptis used here instead ofMD5because BCrypt is a very slow hash function, making brute-force enumeration take a long time.
- The client sends the result of step 3 to the server.
- The server generates a random salt.
SecureRandom random = new SecureRandom(); byte server_salt[] = new byte[36]; random.nextBytes(server_salt); // tq2pdxrblkbgp8vt8kbdpmzdh1w8bex - The server hashes the hash value sent by the client in step 4 together with the random salt generated in step 5.
server_hash = SHA256(client_hash + server_salt); // 55b4b5815c216cf80599990e781cd8974a1e384d49fbde7776d096e1dd436f67- This step is intended to prevent password exposure after a database leak.
- The server stores the result of step 6 and the random salt generated in step 5 in the database.
DB.save(server_hash, server_salt);
2.3. Login Flow
- The user enters the plaintext password.
password = 123456
- The client performs a normal hash on the password.
client_hash = MD5(password) // e10adc3949ba59abbe56e057f20f883e
- The client adds a fixed salt to the result of step 2 and performs a slow hash.
client_hash = BCrypt(MD5(password) + salt) // MFfTW3uNI4eqhwDkG7HP9p2mzEUu/r2
- The client sends the result of step 3 to the server.
- The server retrieves the user’s hash value and salt from the database.
- The server hashes the result of step 4 together with the salt from step 5.
result = SHA256(authentication_hash + server_salt); // 55b4b5815c216cf80599990e781cd8974a1e384d49fbde7776d096e1dd436f67 - Compare the result calculated in step 6 with the hash retrieved in step 5.
3. Phone Number + Verification Code
Login.md (related note not yet public)
4. Third-Party Login
Obtain the third party’s OpenID through OAuth, and then associate the OpenID with the system’s own login state. Login.md (related note not yet public)
Discussion
Sign in with GitHub to comment. Discussions are stored as GitHub Issues.View on GitHub