Beranda

Security

Web Application Security Fundamentals #0...

Web Application Security Fundamentals #08: Authentication & Session Management

Memahami password hashing dengan Argon2id/bcrypt, secure session management, JWT security, MFA implementation, dan brute force defense.

Web Application Security Fundamentals #08: Authentication & Session Management
56 dibaca
Belum ada penilaian

Authentication memverifikasi siapa user. Session management memastikan siapa mereka tetap diketahui di request berikutnya. Keduanya adalah fondasi untuk authorization dan non-repudiation.

Tujuan Pembelajaran

  • Memahami password storage (hashing, salt, algorithms)
  • Implement secure session management
  • Understand JWT (JSON Web Tokens) dan security implications
  • MFA implementation dan recovery codes
  • Brute force defense (rate limiting, account lockout)

Password Storage

✅ Strong Algorithms

# ✅ GOOD - Argon2id (OWASP recommended)
from argon2 import PasswordHasher
ph = PasswordHasher()
hashed = ph.hash("user_password")  # Store this
# Verify:
ph.verify(hashed, "user_password")  # Returns True/False

# ✅ GOOD - bcrypt
import bcrypt
salt = bcrypt.gensalt(rounds=12)
hashed = bcrypt.hashpw(b"password", salt)
# Verify:
bcrypt.checkpw(b"password", hashed)

# ❌ BAD - MD5, SHA1 (too fast, rainbow tables exist)
import hashlib
hashed = hashlib.md5(password).hexdigest()  # Never do this!

Session Token Generation

# ✅ SECURE - Cryptographically random
import secrets
session_id = secrets.token_urlsafe(32)  # 256-bit random

# ❌ INSECURE - Predictable
import time
session_id = str(int(time.time()))  # Guessable!

Secure Session Storage

# ✅ SECURE - HttpOnly, Secure, SameSite
@app.route('/login', methods=['POST'])
def login():
    user = authenticate(request.form['email'], request.form['password'])
    if not user:
        return 'Invalid credentials', 401
    
    session_id = secrets.token_urlsafe(32)
    # Store session server-side (database, Redis)
    Session.create(session_id, user.id, expires_in=3600)
    
    # Send HttpOnly cookie
    resp = make_response({'success': True})
    resp.set_cookie(
        '__Host-session',
        session_id,
        secure=True,          # HTTPS only
        httpOnly=True,        # JS can't access
        sameSite='Lax',       # CSRF protection
        max_age=3600
    )
    return resp

JWT (JSON Web Token) Security

# ✅ SECURE JWT usage
import jwt
from datetime import datetime, timedelta

# Generate
payload = {
    'user_id': 123,
    'exp': datetime.utcnow() + timedelta(hours=1),
    'iat': datetime.utcnow()
}
token = jwt.encode(payload, SECRET_KEY, algorithm='HS256')

# Verify
decoded = jwt.decode(token, SECRET_KEY, algorithms=['HS256'])
# If invalid or expired, exception raised

Common JWT Mistakes

# ❌ DANGEROUS - No signature verification
header, payload, sig = token.split('.')
decoded = json.loads(base64.b64decode(payload))
# Attacker can modify payload without signature check!

# ❌ DANGEROUS - Using 'none' algorithm
# JWT header: {"alg": "none"}
# Attacker send: header.payload. (no signature)

# ✅ SECURE - Strict algorithm check
jwt.decode(token, SECRET_KEY, algorithms=['HS256'])  # Only HS256

Multi-Factor Authentication (MFA)

# Step 1: User login with password
@app.route('/login', methods=['POST'])
def login():
    user = authenticate(email, password)
    if not user:
        return 'Invalid credentials', 401
    
    # Generate MFA challenge
    mfa_token = secrets.token_urlsafe(32)
    cache.set(f'mfa:{mfa_token}', user.id, expire=300)  # 5 min
    
    # Send OTP
    otp = ''.join(str(random.randint(0, 9)) for _ in range(6))
    send_sms(user.phone, f'Your OTP: {otp}')
    cache.set(f'otp:{mfa_token}', otp, expire=300)
    
    return {'mfa_required': True, 'mfa_token': mfa_token}

# Step 2: User submit OTP
@app.route('/mfa-verify', methods=['POST'])
def mfa_verify():
    mfa_token = request.json['mfa_token']
    otp = request.json['otp']
    
    user_id = cache.get(f'mfa:{mfa_token}')
    correct_otp = cache.get(f'otp:{mfa_token}')
    
    if not user_id or otp != correct_otp:
        return 'Invalid OTP', 401
    
    # Create session
    session_id = secrets.token_urlsafe(32)
    Session.create(session_id, user_id)
    
    # Clean up
    cache.delete(f'mfa:{mfa_token}')
    cache.delete(f'otp:{mfa_token}')
    
    return {'session': session_id}

Brute Force Defense

# ❌ VULNERABLE - No rate limiting
@app.route('/login', methods=['POST'])
def login():
    user = User.find_by_email(request.form['email'])
    if not user or not user.verify_password(request.form['password']):
        return 'Invalid', 401
    return {'session': create_session(user)}

# ✅ SECURE - Rate limiting + account lockout
from flask_limiter import Limiter

limiter = Limiter(app, key_func=lambda: request.remote_addr)

@app.route('/login', methods=['POST'])
@limiter.limit('5 per 15 minutes')
def login():
    email = request.form['email']
    user = User.find_by_email(email)
    
    if user and user.locked_until and datetime.utcnow() < user.locked_until:
        return 'Account locked', 429
    
    if not user or not user.verify_password(request.form['password']):
        # Increment failed attempts
        if user:
            user.failed_login_attempts += 1
            if user.failed_login_attempts >= 5:
                user.locked_until = datetime.utcnow() + timedelta(minutes=30)
            user.save()
        
        return 'Invalid', 401
    
    # Successful login
    user.failed_login_attempts = 0
    user.locked_until = None
    user.save()
    
    return {'session': create_session(user)}

Session Fixation Prevention

# ❌ VULNERABLE - Same session ID after login
def login(username, password):
    if verify_credentials(username, password):
        return {'session': request.cookies.get('session')}  # WRONG!

# ✅ SECURE - Regenerate session
def login(username, password):
    if verify_credentials(username, password):
        old_session_id = request.cookies.get('session')
        # Delete old session
        Session.delete(old_session_id)
        
        # Create new session
        new_session_id = secrets.token_urlsafe(32)
        Session.create(new_session_id, user.id)
        return {'session': new_session_id}

Auth Checklist

  • [ ] Passwords hashed dengan Argon2id atau bcrypt
  • [ ] Session ID cryptographically random (256+ bit)
  • [ ] HttpOnly + Secure + SameSite cookie flags
  • [ ] Session timeout (idle + absolute max)
  • [ ] Rate limiting on login (5 attempts/15min)
  • [ ] Account lockout setelah N failed attempts
  • [ ] Session regenerated setelah login
  • [ ] MFA available (TOTP preferred over SMS)
  • [ ] Password reset flow aman (token dengan expiry)
  • [ ] Logout invalidates session
  • [ ] No credential logs atau error messages yang leak

Kesimpulan

Authentication & Session = expensive to break, cheap to implement correctly. Use proven libraries, follow best practices, test thoroughly.

Modul berikutnya (#09) membahas HTTPS, TLS, & Certificate Security.


Next: #09 - HTTPS, TLS, & Encryption

Post Terkait

Malware Analysis Fundamentals #07: Membangun Lab Analisis Malware yang Aman

Panduan membangun lab analisis malware yang aman: isolated VM, snapshot, jaringan host-only/simulasi, mematikan shared c...

15 Sep 2026

Malware Analysis Fundamentals #06: Behavioral & Memory Analysis — Mengamati Perilaku Malware Secara Langsung

Tutorial behavioral & memory analysis malware: mengamati process tree, perubahan file/registry, persistence, trafik C2,...

14 Sep 2026

Malware Analysis Fundamentals #05: Static & Code Analysis — Membedah Malware Tanpa Menjalankannya

Tutorial static & code analysis malware: dari hash dan strings, deteksi packer dengan entropy, sampai disassembly di Ghi...

13 Sep 2026

© 2026 Yowisben. Semua hak dilindungi.

Powered by LONTAR CMS v1.85.0