- Zero-Day Wire
- Posts
- Defend the Web (Week 2): Authentication & Session Management Defense
Defend the Web (Week 2): Authentication & Session Management Defense
How to Build Secure Auth Systems & Stop Credential Attacks
π‘οΈ Week 2: Secure Authentication & Session Management
Defend the Web: Part 2 of 8
Welcome to Defensive Wednesday.
Hey π
Yesterday we broke authentication. You learned how to crack passwords, hijack sessions, and manipulate JWT tokens.
If you missed Week 2 Offensive, read it here π link
Today we flip the script. You're building authentication that actually holds up.
Reality check: 81% of data breaches involve weak or stolen credentials. Authentication is target #1.
π§ What Makes Authentication Secure?
Secure auth = multiple layers:
Strong credential policies
Proper session management
Multi-factor authentication
Rate limiting & monitoring
The goal: Make it so hard attackers move on.
π§ The Defense Process
Step 1: Password Security Done Right
Enforce Strong Policies
Minimum requirements:
12+ characters (length > complexity)
Mix of uppercase, lowercase, numbers, symbols
Block common passwords
Hash Passwords Properly
Use bcrypt or Argon2:
import bcrypt
# Hash password
password = b"user_password"
hashed = bcrypt.hashpw(password, bcrypt.gensalt(rounds=12))
# Verify
if bcrypt.checkpw(password, hashed):
print("Valid")
Why? They're slow by design (~100ms per hash). Makes brute force impractical.
Check Against Breaches
Use Have I Been Pwned API:
import hashlib, requests
def is_pwned(password):
sha1 = hashlib.sha1(password.encode()).hexdigest().upper()
prefix = sha1[:5]
url = f"https://api.pwnedpasswords.com/range/{prefix}"
return sha1[5:] in requests.get(url).text
Step 2: Block Brute Force
Rate Limiting
Limit attempts per IP and account:
from flask_limiter import Limiter
@app.route("/login")
@limiter.limit("5 per minute")
def login():
pass
Account Lockout
Lock after 5 failed attempts for 15 minutes.
CAPTCHA After Failures
Add reCAPTCHA after 3 failed logins.
Progressive Delays
# 1st fail: 0s, 2nd: 2s, 3rd: 4s, 4th: 8s...
delay = min(2 ** (fails - 1), 30)
time.sleep(delay)
Step 3: Prevent Username Enumeration
Generic Errors
β "User not found"
β
"Invalid username or password"
Consistent Response Times
Add artificial delays so valid/invalid usernames take the same time.
Step 4: Secure Session Management
Strong Session Tokens
import secrets
token = secrets.token_urlsafe(32)
Never use predictable tokens.
Secure Cookie Flags
response.set_cookie(
'session_id', token,
httponly=True, # JS can't access
secure=True, # HTTPS only
samesite='Strict' # Prevents CSRF
)
Session Expiration
Implement idle timeout (1 hour) + absolute timeout (24 hours).
Regenerate IDs After Login
Prevents session fixation:
old_session = request.cookies.get('session_id')
delete_session(old_session)
new_session = secrets.token_urlsafe(32)
Step 5: Defend Against JWT Attacks
Use Strong Algorithms
β Never: none algorithm
β
Use: HS256 with 32+ byte secrets or RS256
Validate Everything
import jwt
payload = jwt.decode(
token, secret,
algorithms=['HS256'],
options={'verify_signature': True, 'verify_exp': True}
)
Short Expiration
Access tokens: 15 minutes
Refresh tokens: 7 days
Token Revocation
Use Redis blacklist:
import redis
r = redis.Redis()
def logout(token):
exp = jwt.decode(token, secret)['exp']
r.setex(f"blacklist:{token}", int(exp - time.time()), "1")
Step 6: Implement MFA
TOTP (Google Authenticator)
import pyotp
secret = pyotp.random_base32()
totp = pyotp.TOTP(secret)
# Verify code
totp.verify(user_code, valid_window=1)
Backup Codes
Generate 10 one-time codes, hash them, show once.
Prevent MFA Bypass
No session tokens before MFA verification
Rate limit MFA attempts (3 max)
Invalidate codes after use
Step 7: Monitor & Detect
Log Everything
log_entry = {
'timestamp': time.time(),
'event': 'login',
'username': username,
'ip': request.remote_addr,
'success': True
}
Watch For:
Logins from new locations
Multiple failed attempts
Impossible travel (5000km in 1 hour)
Simultaneous logins from different IPs
Geolocation Checks
def check_impossible_travel(user_id, current_ip):
last_login = get_last_login(user_id)
distance = calculate_distance(last_ip, current_ip)
time_diff = time.time() - last_login['time']
if distance > 5000 and time_diff < 3600:
lock_account(user_id)
Step 8: Secure Password Reset
Time-Limited Tokens
import secrets, hashlib
raw_token = secrets.token_urlsafe(32)
token_hash = hashlib.sha256(raw_token.encode()).hexdigest()
store_reset_token(user_id, token_hash, expires_in=3600)
Invalidate After Use
Delete token after password reset. Invalidate all sessions.
Prevent Email Enumeration
Always return: "If that email exists, we've sent a reset link."
Step 9: SQL Injection Prevention
Use Parameterized Queries
β Never:
f"SELECT * FROM users WHERE username='{user}'"
β Always:
cursor.execute("SELECT * FROM users WHERE username=?", (user,))
Use ORMs
SQLAlchemy, Django ORM, etc. handle this automatically.
Step 10: Secure OAuth
Validate redirect_uri
Whitelist allowed redirect URIs.
Use state Parameter
state = secrets.token_urlsafe(32)
session['oauth_state'] = state
# On callback
if request.args.get('state') != session.get('oauth_state'):
return "CSRF detected"
π οΈ Tool List
Password Security
bcrypt β pypi.org/project/bcrypt
Argon2 β github.com/P-H-C/phc-winner-argon2
HIBP API β haveibeenpwned.com/API/v3
Rate Limiting
Flask-Limiter β flask-limiter.readthedocs.io
express-rate-limit β npmjs.com/package/express-rate-limit
reCAPTCHA β google.com/recaptcha
Session Management
Redis β redis.io
Flask-Session β flask-session.readthedocs.io
JWT
PyJWT β pyjwt.readthedocs.io
jsonwebtoken β npmjs.com/package/jsonwebtoken
MFA
pyotp β pyauth.github.io/pyotp
Google Authenticator β App stores
Authy β authy.com
Monitoring
ELK Stack β elastic.co/elk-stack
Datadog β datadoghq.com
Sentry β sentry.io
β Week 2 Checklist
[ ] Strong password policies (12+ chars)
[ ] bcrypt/Argon2 hashing
[ ] HIBP breach checking
[ ] Rate limiting (5 attempts/min)
[ ] Account lockout after 5 fails
[ ] Generic error messages
[ ] Cryptographically random tokens
[ ] HttpOnly/Secure/SameSite cookies
[ ] Session expiration (idle + absolute)
[ ] Session regeneration after login
[ ] JWT signature validation
[ ] Short JWT expiration (15 min)
[ ] MFA implemented (TOTP)
[ ] Authentication logging
[ ] Suspicious activity monitoring
[ ] Secure password reset flow
[ ] Parameterized queries only
π― Key Takeaways
β
Passwords aren't enough β Use MFA always
β
Hash, don't encrypt β bcrypt/Argon2 with high cost
β
Protect session tokens β HttpOnly, Secure, SameSite flags
β
Rate limit everything β Stop brute force automation
β
Generic error messages β No username enumeration
β
Log everything β Can't defend what you can't see
β
Test yourself β Use attacker tools on your own systems
β
Defense is continuous β Monitor, update, stay vigilant
Next Tuesday: Access Control & IDOR attacks
Next Wednesday: Proper access control implementation
Stay secure π‘οΈ
Your Feedback MattersDid You Enjoy This Weekβs Defensive Tutorial? |
β Zwire βοΈ
P.S. Questions? Reply to this email. I read everything.
Reply