Password Hashing and Safe Credential Storage: What a Login Database Should Actually Contain
A practical guide to password hashing, salts, work factors, reset flows, and why encrypting passwords is not the same as safely storing them.
Password storage should use a dedicated password-hashing function with a unique salt and an appropriate work factor, so the server can verify guesses without storing recoverable passwords. Use the subject as a system to inspect, not a checklist to memorize. The goal is to be able to explain where the trust boundary or failure mode sits when a real project changes.
The core idea
Passwords are low-entropy secrets chosen by humans, so attackers can guess them. Ordinary fast hashes are designed to be efficient, which is the opposite of what a password database needs. Password-hashing algorithms deliberately make each guess more expensive and incorporate salts so identical passwords do not automatically produce identical stored values.
How it works in practice
During registration, the server generates a unique salt and runs the password through the chosen password-hashing function. The resulting record stores the parameters and hash needed for later verification.
At login, the server repeats the function using the supplied password and stored salt and parameters, then verifies the result using a constant-time comparison strategy provided by the library or runtime.
Password resets should use separate short-lived random recovery credentials. The reset token is not the password and should have its own expiration, scope, and invalidation behavior.
A concrete example
Two users who choose the same password can still have different stored password hashes when unique salts are used. An attacker who steals the database then has to perform expensive password guesses for each record rather than simply comparing identical hashes.
A useful exercise is to predict the attack or failure path before looking at the fix. Then ask whether the control prevents the event, limits its impact, or merely detects it.
Common mistakes
- Using SHA-256 or another general-purpose hash directly for passwords.
- Storing plaintext passwords 'just for development' and later copying the schema into production.
- Logging passwords or reset tokens while debugging authentication.
A student project that makes it stick
Build a local registration and login service using a well-reviewed password-hashing library. Add tests for duplicate passwords, wrong passwords, password reset expiration, and logging behavior. Never create your own cryptographic primitive.
Where it connects
Security almost never lives in one file. It crosses browsers, APIs, databases, CI runners, credentials, operating systems, and human workflows. That is why simple architectural diagrams are often more useful than a very long vulnerability list.
Practical checklist
- Identify the asset and the trust boundary.
- Decide what must be prevented and what can instead be detected.
- Reduce permissions and lifetime wherever possible.
- Add a test or observable signal for important controls.
- Revisit the design after dependencies or architecture change.
Limitations
Security guidance is contextual. A control that fits a public web application may not fit a local CLI tool, and a demo environment may expose different risks from production. Use the primary references below for implementation details and adapt them to the actual system you control.
Related Observatory reads
- authentication sessions and tokens
- secrets management for student projects
- threat modeling for student projects
Primary sources
Evidence
Sources & further reading
Primary sources, official disclosures, and external research used to ground this report.
- OWASP — Password Storage Cheat Sheetcheatsheetseries.owasp.org
Primary security guidance on password hashing and storage.
- NIST SP 800-63Bpages.nist.gov
Digital identity guidance covering memorized secrets.
Keep Exploring
Related observations.
Threat Modeling for Student Projects: Find the Dangerous Assumptions Before Attackers Do
Threat modeling is simply asking what you are protecting, who can influence the system, and what breaks when an assumption fails.
SQL Injection and Safe Database Queries: Why Parameters Beat String Concatenation
SQL injection happens when untrusted input changes the structure of a database command. Parameterized queries keep data in the data channel.
Secure Dependencies and the Software Supply Chain: Your Code Is Not the Whole Program
Modern projects execute thousands of lines written by other people. Supply-chain security is the discipline of knowing what you depend on and how it enters the build.