jypi
  • Explore
ChatWays to LearnMind mapAbout

jypi

  • About Us
  • Our Mission
  • Team
  • Careers

Resources

  • Ways to Learn
  • Mind map
  • Blog
  • Help Center
  • Community Guidelines
  • Contributor Guide

Legal

  • Terms of Service
  • Privacy Policy
  • Cookie Policy
  • Content Policy

Connect

  • Twitter
  • Discord
  • Instagram
  • Contact Us
jypi

© 2026 jypi. All rights reserved.

CS50 - Web Programming with Python and JavaScript
Chapters

1Orientation and Web Foundations

2Tools, Workflow, and Git

3HTML5 and Semantic Structure

4CSS3, Layouts, and Responsive Design

5Python Fundamentals for the Web

6Flask, Routing, and Templates

7Data, SQL, and ORM Patterns

8State, Sessions, and Authentication

Cookies and storage optionsFlask sessions configurationServer side session storesPassword hashing and saltingUser registration flowsLogin and logout flowsAccess control and rolesCSRF protection patternsOAuth and social loginJWT and token based authEmail verification flowsRemember me functionalityRate limiting strategiesAudit logs and user activityPrivacy and data protection

9JavaScript Essentials and the DOM

10Asynchronous JS, APIs, and JSON

11Frontend Components and React Basics

12Testing, Security, and Deployment

Courses/CS50 - Web Programming with Python and JavaScript/State, Sessions, and Authentication

State, Sessions, and Authentication

23551 views

Handle user state securely and implement authentication and authorization flows.

Content

4 of 15

Password hashing and salting

Password Hashing and Salting Explained for CS50 Web
6259 views
beginner
security
web-development
python
flask
gpt-5-mini
6259 views

Versions:

Password Hashing and Salting Explained for CS50 Web

Watch & Learn

AI-discovered learning video

Sign in to watch the learning video for this topic.

Sign inSign up free

Start learning for free

Sign up to save progress, unlock study materials, and track your learning.

  • Bookmark content and pick up later
  • AI-generated study materials
  • Flashcards, timelines, and more
  • Progress tracking and certificates

Free to join · No credit card required

Password Hashing and Salting — Securely Storing User Secrets (CS50 Web Programming)

"Passwords are like underwear: change them often, don’t share them, and don’t leave them lying around in a public database." — Probably me, after reading a DB dump.

You’ve already learned how to configure Flask sessions and where to store session data (server-side stores vs signed cookies). Now we’re stepping back a layer: how do you safely put users’ passwords into the database your ORM manages? That’s where password hashing and salting come in — the non-sexy, absolutely essential plumbing of authentication.


What this is (in one dramatic sentence)

Password hashing = turn a password into a fixed-length, irreversible fingerprint. Salting = add unique randomness so fingerprints aren’t identical across identical passwords.

Why this matters: if an attacker steals your users table, you don’t want plain text logins. You want slow, salted hashes that make cracking expensive and rainbow tables useless.


Quick reminder: how this ties to what you already know

  • You store user records in a database (we covered Model/ORM and migrations). The password field in that model should never be plain text.
  • When a user logs in you verify credentials and then create a session (server-side session store or a properly configured Flask session). But password verification happens first — compare the hashed password you stored with the hash of what the user submitted.

So this topic sits between your model layer and session creation: store hashed passwords in the DB, verify at login, then open a session.


Real-world analogies (because metaphors stick)

  • Hashing = meat grinder. You put the steak (password) in, you get ground beef (hash). You cannot reassemble the steak.
  • Salt = spice mix unique to each batch. If everyone uses the same spice, someone could identify identical burgers. Unique salts mean identical steaks produce different ground beef.
  • Pepper = secret server-side additive. If an attacker steals the DB but not the pepper jar (an env var kept safe), it’s harder to reverse hashes.

Important properties of a good password hash

  • One-way: cannot feasibly reverse.
  • Deterministic given same input + salt: same password+salt gives same hash so you can verify.
  • Slow / adjustable work factor: slows down brute-force. Increase cost as hardware improves.
  • Unique per-password salt: prevents precomputed attack (rainbow tables).
  • Well-tested libraries: don’t roll your own crypto.

Never use general-purpose fast hashes (MD5, SHA1, SHA256) for password storage. Use bcrypt, Argon2, PBKDF2, or scrypt.


Practical code (Flask + ORM style)

Example using Werkzeug (simple) and bcrypt (recommended for cost control). Werkzeug's generate_password_hash uses PBKDF2 by default; modern projects often use bcrypt or Argon2.

Registration (storing hashed password)

# Using werkzeug.security
from werkzeug.security import generate_password_hash

# in your user registration handler
password = request.form['password']
hash = generate_password_hash(password)  # default: pbkdf2:sha256 with salt

# store `hash` in your users table (e.g., User.password_hash)
user = User(username=username, password_hash=hash)
db.session.add(user)
db.session.commit()

Login (verifying)

from werkzeug.security import check_password_hash

# in login handler
user = User.query.filter_by(username=username).first()
if user and check_password_hash(user.password_hash, submitted_password):
    # password ok -> create session
    session['user_id'] = user.id
else:
    # invalid credentials

Note: modern libraries embed salt and cost parameters into the hash string, so you don’t need to manage salts separately.


Upgrading from legacy plaintext or weak hashes (migration strategy)

You’ve got users with bad hashes (or worse, plaintext). Best practice:

  1. Add a new column (e.g., password_hash_new) via migration, keep legacy data until migrated.
  2. On login: if user has legacy password or weak hash, verify using the old method, then immediately generate and store a new strong hash. This migrates users silently as they log in.
  3. For users who don’t log in, force password reset or bulk rehash with a secure flow (email token).

This avoids mass-reset headaches and minimizes exposure.


Salts, peppers, and storage details

  • Salt: random per password. Stored with the hash (or embedded in it). Modern schemes (bcrypt, Argon2) include the salt in the hash string. You do not need to store a separate salt column anymore.
  • Pepper: a global secret stored outside the DB (e.g., in an environment variable). You can prepend/append pepper to passwords before hashing. Pros: if DB is stolen but server secret isn’t, attacker still lacks full data. Cons: if pepper leaks you’re back to square one; and pepper complicates password resets and migration.
  • Cost/work factor: store the parameters of the algorithm so you can increase cost later. Good libs include these parameters in the hash output.

Why not just hash with SHA256? (common misconception)

SHA256 is fast. That’s great for checksums, not passwords. Attackers can try millions of SHA256 guesses per second on GPUs. Use deliberately slow functions (bcrypt, Argon2) that are computationally expensive or memory-hard.


Security checklist (practical)

  • Use a proven library: bcrypt, Argon2, or PBKDF2 from a reputable lib.
  • Ensure per-password salt (usually automatic).
  • Set an appropriate cost/work factor and plan to increase it over time.
  • Never store plain text passwords.
  • Use constant-time comparison functions (provided by libs) to avoid timing attacks.
  • Do password resets via tokens — never email passwords.
  • Consider a pepper if you have strict threat models and manage secrets safely.

Example: rehash on successful login (pseudo)

# After user successfully logs in
if needs_rehash(user.password_hash):
    new_hash = generate_password_hash(submitted_password)  # with new stronger params
    user.password_hash = new_hash
    db.session.commit()

This pattern lets you upgrade hashing algorithms gradually.


Closing: Key takeaways (the things you’ll use tomorrow)

  • Never store plain text passwords. Ever.
  • Use bcrypt / Argon2 / PBKDF2 via well-reviewed libraries — they handle salts and costs for you.
  • Store the hash in your ORM-managed users table, verify at login, then create the session.
  • Salt per password prevents rainbow table attacks; work factor slows brute force.
  • Plan for migration: rehash users on login, and require reset where needed.

"This is the moment where the concept finally clicks." — Because now you know that hashing + salting = less nightmares the next time someone downloads your users table.


If you want, I can: provide a Flask blueprint with registration/login handlers using bcrypt, or show a migration pattern to convert old plaintext passwords safely. Which would help you sleep better at night?

Flashcards
Mind Map
Speed Challenge

Comments (0)

Please sign in to leave a comment.

No comments yet. Be the first to comment!

Ready to practice?

Sign up now to study with flashcards, practice questions, and more — and track your progress on this topic.

Study with flashcards, timelines, and more
Earn certificates for completed courses
Bookmark content for later reference
Track your progress across all topics