Skip to main content

Auth, Secrets, and Hardening

advanced30 min readLesson 157 of 169

Password hashing done right, session hygiene, secret management, and the security headers that cost nothing.

Passwords: hashing is not encryption

You must never be able to read a password back. Store hash(password + salt) with a slow, memory-hard function โ€” bcrypt, scrypt, or Argon2. Slow is the point: an offline attacker with your database makes billions of guesses; each guess must cost real time. (hashlib.sha256 is fast โ€” that's why it's wrong here.) Salts kill rainbow tables; work factors make brute force uneconomical; rate limiting on the login endpoint caps online guessing.

Sessions and cookies

After login, the server issues a random session ID (โ‰ฅ128 bits of entropy) kept in a cookie. Hardening flags:

  • HttpOnly โ€” JavaScript cannot read it (XSS can't steal it),
  • Secure โ€” it never travels over plain HTTP,
  • SameSite=Lax โ€” cross-site requests don't carry it (kills most CSRF),
  • expiring and rotating IDs on privilege changes.

CSRF, the leftover case: an attacker's page makes the victim's browser send an authenticated request. SameSite blocks most; a synchronizer token (a random value in the form that must match the session) blocks the rest.

Secrets: config, not code

A secret in source control is compromised forever (history survives deletion). The discipline: secrets live in environment variables or a secrets manager, loaded at startup, validated with the same parse-don't-validate discipline as any boundary input (SECRET_KEY missing โ†’ refuse to boot, don't default). Different environments get different secrets; logs and error reports are scrubbed of them; dependencies are pinned and audited (pip audit) because your supply chain is also an attack surface.

Security headers: the cheapest fixes in the file

| Header | Effect | |---|---| | Content-Security-Policy | blocks script from unapproved origins | | X-Content-Type-Options: nosniff | browser won't reinterpret responses | | Strict-Transport-Security | forces HTTPS for future visits | | X-Frame-Options: DENY | blocks clickjacking via framing |

Verification closes the loop

A fix without a test is a hope. Every security change ships with a test that proves the attack fails now: the traversal path is rejected, the injection string is stored as a literal, the wrong owner gets 403/404. That's the checkpoint below.

Now practice

Authorization & Session DrillsOwnership checks that derive from the session, and password hashing with real entropy rules.2 challenges ยท ยท ~22 minHardening DrillsThe full password checker with its ordered diagnostics, and a secrets loader that refuses to boot without configuration.2 challenges ยท ยท ~20 min