Chapter 9 — Data and databases
Lesson map
Lesson 09 published. Map, example, EX025.
flowchart TD
N0["Learning outcomes"]
N1["9.1 Password storage"]
N2["Lab — Salted password hashing"]
N3["9.2 Reading the run"]
N4["9.3 Field-level choices"]
N5["Synthesis"]
N0 --> N1 --> N2 --> N3 --> N4 --> N5
N5 --> EX["Worked example"]
EX --> Q["Exercise EX025"]
Logical drawing
flowchart LR
N0["Learning outcomes"]
N1["9.1 Password storage"]
N2["Lab — Salted password hashing"]
N3["9.2 Reading the run"]
N4["9.3 Field-level choices"]
N5["Synthesis"]
N0 --> N1 --> N2 --> N3 --> N4 --> N5 --> Q["EX025"]
[Learning outcomes]
|
v
[9.1 Password storage]
|
v
[Lab — Salted password hashing]
|
v
[9.2 Reading the run]
|
v
[9.3 Field-level choices]
|
v
[Synthesis]
|
v
[Worked example] --> [Exercise EX025]
Learning outcomes
You will (1) store passwords with salted, slow hashing; (2) explain why salts and work factors matter; (3) choose field-level protections in a database.
9.1 Password storage
Tidewell's old portal stored passwords with plain SHA-256, which Priya explains is unsafe: SHA-256 is fast, so an attacker with a stolen table can test billions of guesses per second, and identical passwords produce identical hashes. A proper scheme adds a unique random salt per user and uses a deliberately slow function. RFC 9106 specifies Argon2id, the preferred choice; PBKDF2, available in Python's hashlib, is an older fallback that needs a high iteration count. The lab demonstrates salting with PBKDF2 because it is in the standard library.
Lab — Salted password hashing
"""Salted password hashing with hashlib.pbkdf2_hmac on synthetic passwords (prefer Argon2id, RFC 9106)."""
import hashlib, hmac
def h(pw, salt, n=600_000):
return hashlib.pbkdf2_hmac("sha256", pw.encode(), salt, n).hex()
def main():
s1, s2 = bytes.fromhex("a1" * 16), bytes.fromhex("b2" * 16) # fixed demo salts for reproducible output
a, b = h("correct horse 42", s1), h("correct horse 42", s2)
print("same password, different salts differ:", a != b)
print("stored:", a[:24], "...")
print("login with right password:", hmac.compare_digest(a, h("correct horse 42", s1)))
print("login with wrong password:", hmac.compare_digest(a, h("correct horse 43", s1)))
if __name__ == "__main__":
main()
Run with python3 lab_pbkdf2.py. Verified output:
same password, different salts differ: True
stored: c96866459ba12d6a7bc6285d ...
login with right password: True
login with wrong password: False
9.2 Reading the run
The same password with two different salts produces different stored values, so an attacker cannot see which patrons share a password or use precomputed tables. Logging in with the right password recomputes the same value and compare_digest returns True; a one-character change returns False. The fixed demonstration salts exist only to make the output repeatable; real salts come from secrets.token_bytes. The 600,000 iterations slow each guess. Priya recommends migrating to Argon2id, rehashing each password at the patron's next successful login.
9.3 Field-level choices
Beyond passwords, Priya classifies database fields: names and addresses are encrypted at the field level with keys from the consortium's key service; loan history older than ninety days is deleted, following the privacy principle of keeping only what is needed; and patron card numbers are tokenised for reporting systems. She records that deleting old data is often the strongest protection, since data that does not exist cannot leak. Grace agrees and schedules the retention change after board approval. The policy is published for patrons.
Worked example
Priya replaces plain SHA-256 with salted slow hashing, plans migration to Argon2id at next login, encrypts personal fields and deletes loan history after ninety days.
Synthetic case. Tidewell's database is invented; RFC 9106 is real.
Errors and limits
Slow hashing does not save very weak passwords. Encryption keys stored beside the database offer little protection.
Exercises
- EX025 — Why SHA-256 fails. Why is plain SHA-256 unsafe for passwords? Rubric: 3 = fast, enabling billions of guesses, and identical passwords give identical hashes;; 2 = fast;; 1 = it is fine;; 0 = none.
- EX026 — Salt effect. What did the lab show about salts? Rubric: 3 = same password with different salts gives different stored values;; 2 = differ;; 1 = same;; 0 = none.
- EX027 — Strongest protection. What does Priya call often the strongest protection? Rubric: 3 = deleting data that is not needed;; 2 = deletion;; 1 = encryption;; 0 = none.
Synthesis
Salted, slow password hashing, field encryption and data minimisation protect patron data in databases.
Continue studying — chapter 09 of 40
← Chapter 08 (draft) · Course chapter index · Chapter 10 (draft) →