Passwords, multi-factor authentication, and session protection
Objectives
By the end of the lesson, you can say how a password must be stored and why a fast hash is not good, what multi-factor authentication (MFA) means and what it does not solve, and what must be done to protect the session identifier.
Why does the security of login not end with checking the password?
The security of login consists of several links: the storage of the password, the second factor, the handling of the session identifier, and logout. One weak link is enough for account takeover. The attacker can steal the password from a database leak, guess it, phish it, or obtain the session identifier valid after login. Each needs a separate defense.
Checking and storing the password
At login the server compares the given password with the verification value stored earlier. The password must not be stored in readable form, because a database leak would reveal it at once. Storage requires a password hash: a one-way transformation from which the password cannot be restored.
But it matters what kind of hash. A fast, general-purpose hash (for example SHA-256, Secure Hash Algorithm) is good for files precisely because it is fast; for passwords this is the problem, because the attacker can try a great many guesses quickly. We tried it on the same machine, on one core:
SHA-256: 20000 tries in 16 ms (~1 288 269 tries/s)
scrypt (N=2^17, r=8, p=1): 20 tries in 3457 ms (~6 tries/s)
The fast hash is more than two hundred thousand times faster. An attacker who has obtained the hashes can try several million passwords per second with plain SHA-256, and only a few with the costly procedure. That is why passwords need a procedure designed specifically for this, slow and resource-intensive.
OWASP's password storage guide recommends the following order:
Argon2id (primary): at least 19 MiB of memory, 2 iterations, parallelism of 1;
scrypt, if Argon2id is not available (at least N=2^17, r=8, p=1);
bcrypt for legacy systems (with a work factor of at least 10, and a 72-byte password length limit, because it truncates anything longer);
PBKDF2, if it is mandatory for compliance reasons (PBKDF2-HMAC-SHA256 with at least 600,000 iterations).
(PBKDF2: Password-Based Key Derivation Function 2.) The measurement above was made with scrypt, because according to our try there is no argon2Sync function in the built-in crypto module of Node.js 24.4.1; in a production system a proven library must be used, never a home-made implementation.
Salt
Every password has a unique, random salt. This prevents the use of precomputed tables, and prevents the attacker from cracking many hashes in one go. Tried with the same password and two different salts:
same password, two different salts:
0c4b569047729615f0fccb2af461261c...
44b17cf13358073209130e40f14c5c1d...
The stored values for the same passwords differ, so from a leak it cannot be seen who used the same password. Most libraries manage the salt automatically.
flowchart LR
P[User's password] --> H[Slow password hash + unique salt]
H --> D[(Stored verification value)]
X[Password given at login] --> V[Verification by the same procedure]
D --> V
V --> R{Match?}
Password use and recovery
According to NIST's (National Institute of Standards and Technology) authentication guideline (SP 800-63B), for passwords length counts: for a standalone password at least 15 characters, with a permitted length of at least 64 characters; mandatory character-mix rules must not be imposed; regular password change must not be forced (only on compromise); the new password must be checked against lists of known, common, or leaked passwords; and password managers and pasting must be allowed. On the server side, limiting the number of attempts and detecting incidents are important.
Password reset can be an account-takeover route just as login can, so the recovery process cannot be weaker than login.
Multi-factor authentication
MFA (Multi-Factor Authentication) combines at least two different factor families: something we know (a password), something we possess (an authenticator device, a security key), or something that is tied to the person (biometrics). Two passwords requested one after the other are not two factors. MFA reduces the value of a stolen password, but does not make account takeover impossible: phishing, session theft, or poorly protected recovery remain risks.
The strength of the methods differs. According to NIST's guideline, passwords, one-time codes (OTP: one-time password), and codes sent by SMS or another channel are not phishing-resistant, because the user can be talked into passing them on. Phishing-resistant is cryptographic authentication bound to the given website (in the browser, to the origin), such as a security key based on WebAuthn/FIDO2. The point from the course's perspective: the factor should really be independent evidence, and the recovery route should not bypass the login protection more easily.
The session as a post-login key
After successful authentication the session identifier or access token proves in later requests that the client is continuing an already logged-in flow (7.2, 7.3). Whoever obtains this value can use the session without knowing the password. Therefore:
the identifier should be hard to guess (random, long enough);
at login and at a change of privilege state it is worth issuing a new identifier (against session fixation);
there should be expiry and server-side invalidation;
the cookie should be Secure (binds it to a protected connection), HttpOnly (JavaScript cannot read it directly), and SameSite (regulates cross-site sending). These act against separate risks: HttpOnly does not stop every operation of a script running on a compromised page (8.3), and SameSite is not complete CSRF protection (8.4).
Keeping an authentication token in the localStorage or sessionStorage of the browser, reachable from JavaScript, is risky, because in case of XSS the script can access it; the decision about storage must be made on the basis of the threat model (8.1).
Logout and time limits
Depending on the authentication levels, NIST prescribes different re-authentication time limits (shorter at higher levels), which shows well that time limits are proportional to risk.
Worked example: logging in to Kurzuspont
Element
Decision
Password storage
Argon2id or scrypt, a unique salt, with a proven library.
Password requirement
At least 15 characters, long passwords, leaked passwords banned, no mandatory character mix or forced change.
Attempts
Limiting and an alert for many failed logins (chapter 10: observability).
MFA
Mandatory for instructors, recommended for students; a phishing-resistant method preferred.
Recovery
A one-time, short-lived link; not weaker than login.
Session
Random identifier, new at login, HttpOnly; Secure; SameSite, short expiry, server-side logout.
Common misconceptions
Statement
Clarification
"A password hashed with SHA-256 can be stored safely."
For passwords a costly procedure designed for the purpose and a unique salt are needed.
"After MFA the session no longer matters."
An obtained session identifier may still be usable.
"HttpOnly defends against every browser attack."
It limits only the direct script access to the cookie.
"Logout is only client-side state."
The server must also invalidate the accepted access.
"An SMS code is phishing-resistant."
According to NIST, such codes can be passed on, so they are not.
"A complicated password is better than a long one."
Length counts; NIST does not prescribe a mandatory character mix.
In brief
Store the password with a slow, purpose-designed hash and a unique salt (Argon2id, scrypt); a fast hash (SHA-256) is not good.
The tried fast hash was ~1.3 million tries/s, scrypt ~6 tries/s on the same machine.
MFA combines different factor families; the strongest are the phishing-resistant methods.
The session identifier is a post-login key: random, new at login, expiring, invalidatable on the server.
Review questions
Why is plain SHA-256 not good for password storage?
What does the salt protect?
What is the difference between MFA and two passwords in a row?
Why must logout invalidate the session on the server too?
Passwords, multi-factor authentication, and session protection
Objectives
By the end of the lesson, you can say how a password must be stored and why a fast hash is not good, what multi-factor authentication (MFA) means and what it does not solve, and what must be done to protect the session identifier.
Why does the security of login not end with checking the password?
The security of login consists of several links: the storage of the password, the second factor, the handling of the session identifier, and logout. One weak link is enough for account takeover. The attacker can steal the password from a database leak, guess it, phish it, or obtain the session identifier valid after login. Each needs a separate defense.
Checking and storing the password
At login the server compares the given password with the verification value stored earlier. The password must not be stored in readable form, because a database leak would reveal it at once. Storage requires a password hash: a one-way transformation from which the password cannot be restored.
But it matters what kind of hash. A fast, general-purpose hash (for example SHA-256, Secure Hash Algorithm) is good for files precisely because it is fast; for passwords this is the problem, because the attacker can try a great many guesses quickly. We tried it on the same machine, on one core:
The fast hash is more than two hundred thousand times faster. An attacker who has obtained the hashes can try several million passwords per second with plain SHA-256, and only a few with the costly procedure. That is why passwords need a procedure designed specifically for this, slow and resource-intensive.
OWASP's password storage guide recommends the following order:
(PBKDF2: Password-Based Key Derivation Function 2.) The measurement above was made with scrypt, because according to our try there is no
argon2Syncfunction in the built-incryptomodule of Node.js 24.4.1; in a production system a proven library must be used, never a home-made implementation.Salt
Every password has a unique, random salt. This prevents the use of precomputed tables, and prevents the attacker from cracking many hashes in one go. Tried with the same password and two different salts:
The stored values for the same passwords differ, so from a leak it cannot be seen who used the same password. Most libraries manage the salt automatically.
flowchart LR P[User's password] --> H[Slow password hash + unique salt] H --> D[(Stored verification value)] X[Password given at login] --> V[Verification by the same procedure] D --> V V --> R{Match?}Password use and recovery
According to NIST's (National Institute of Standards and Technology) authentication guideline (SP 800-63B), for passwords length counts: for a standalone password at least 15 characters, with a permitted length of at least 64 characters; mandatory character-mix rules must not be imposed; regular password change must not be forced (only on compromise); the new password must be checked against lists of known, common, or leaked passwords; and password managers and pasting must be allowed. On the server side, limiting the number of attempts and detecting incidents are important.
Password reset can be an account-takeover route just as login can, so the recovery process cannot be weaker than login.
Multi-factor authentication
MFA (Multi-Factor Authentication) combines at least two different factor families: something we know (a password), something we possess (an authenticator device, a security key), or something that is tied to the person (biometrics). Two passwords requested one after the other are not two factors. MFA reduces the value of a stolen password, but does not make account takeover impossible: phishing, session theft, or poorly protected recovery remain risks.
The strength of the methods differs. According to NIST's guideline, passwords, one-time codes (OTP: one-time password), and codes sent by SMS or another channel are not phishing-resistant, because the user can be talked into passing them on. Phishing-resistant is cryptographic authentication bound to the given website (in the browser, to the origin), such as a security key based on WebAuthn/FIDO2. The point from the course's perspective: the factor should really be independent evidence, and the recovery route should not bypass the login protection more easily.
The session as a post-login key
After successful authentication the session identifier or access token proves in later requests that the client is continuing an already logged-in flow (7.2, 7.3). Whoever obtains this value can use the session without knowing the password. Therefore:
Secure(binds it to a protected connection),HttpOnly(JavaScript cannot read it directly), andSameSite(regulates cross-site sending). These act against separate risks:HttpOnlydoes not stop every operation of a script running on a compromised page (8.3), andSameSiteis not complete CSRF protection (8.4).Keeping an authentication token in the
localStorageorsessionStorageof the browser, reachable from JavaScript, is risky, because in case of XSS the script can access it; the decision about storage must be made on the basis of the threat model (8.1).Logout and time limits
Depending on the authentication levels, NIST prescribes different re-authentication time limits (shorter at higher levels), which shows well that time limits are proportional to risk.
Worked example: logging in to Kurzuspont
HttpOnly; Secure; SameSite, short expiry, server-side logout.Common misconceptions
HttpOnlydefends against every browser attack."In brief
Review questions
Learning resources