Day 04 Cryptography

Cryptography for Developers

TLS handshakes, symmetric vs asymmetric encryption, certificate pinning, key management, and the crypto mistakes that compromise production systems.

~1 hour Intermediate Hands-on Precision AI Academy

Today's Objective

TLS handshakes, symmetric vs asymmetric encryption, certificate pinning, key management, and the crypto mistakes that compromise production systems.

01

Rate Limiting Login Endpoints

Terminal

npm install express-rate-limit

rate-limit.js
const rateLimit = require('express-rate-limit');

// General API rate limit
const apiLimiter = rateLimit({
  windowMs: 15 * 60 * 1000,  // 15 minutes
  max: 100,                    // 100 requests per window
  standardHeaders: true,
  legacyHeaders: false,
  message: { error: 'Too many requests, please try again later' }
});

// Strict limit for auth endpoints
const authLimiter = rateLimit({
  windowMs: 15 * 60 * 1000,
  max: 5,  // 5 attempts per 15 minutes
  skipSuccessfulRequests: true, // Don't count successful logins
  handler: (req, res) => {
    res.status(429).json({
      error: 'Too many login attempts. Try again in 15 minutes.'
    });
  }
});

app.use('/api/', apiLimiter);
app.use('/login', authLimiter);
app.use('/register', authLimiter);
02

Secure Password Hashing with bcrypt

Password Security
const bcrypt = require('bcrypt');
const SALT_ROUNDS = 12; // Higher = slower to crack, slower to compute

// On registration: hash the password
async function register(email, plainPassword) {
  const hash = await bcrypt.hash(plainPassword, SALT_ROUNDS);
  await User.create({ email, passwordHash: hash });
}

// On login: compare password to hash
async function login(email, plainPassword) {
  const user = await User.findByEmail(email);
  if (!user) {
    // Still compare to prevent timing attacks
    await bcrypt.compare(plainPassword, '$2b$12$invalid.hash.padding');
    return null;
  }
  
  const valid = await bcrypt.compare(plainPassword, user.passwordHash);
  return valid ? user : null;
}

// Password strength validation
function isStrongPassword(password) {
  return (
    password.length >= 12 &&
    /[A-Z]/.test(password) &&
    /[0-9]/.test(password) &&
    /[^A-Za-z0-9]/.test(password)
  );
}
Day 4 Exercise
Add Rate Limiting to Your App
  1. Add express-rate-limit and configure both the general API limiter and the strict auth limiter.
  2. Test the auth limiter: make 6 rapid POST requests to /login and verify the 6th is blocked.
  3. Verify that successful logins don't count toward the limit (skipSuccessfulRequests).
  4. Check that your registration flow hashes passwords with bcrypt before storing.

Day 4 Summary

What's Next

The foundations from today carry directly into Day 5. In the next session the focus shifts to Security Headers, CORS, and CSP — building directly on everything covered here.

Day 4 Checkpoint

Before moving on, verify you can answer these without looking:

  • What is the core concept introduced in this lesson, and why does it matter?
  • What are the two or three most common mistakes practitioners make with this topic?
  • Can you explain the key code pattern from this lesson to a colleague in plain language?
  • What would break first if you skipped the safeguards or best practices described here?
  • How does today's topic connect to what comes in Day 5?

Live Bootcamp

Learn this in person — 2 days, 5 cities

Thu–Fri sessions in Denver, Los Angeles, New York, Chicago, and Dallas. $1,490 per seat. June–October 2026.

Reserve Your Seat →
Continue To Day 5
Day 5