BAB 14 - KEAMANAN WEBSITE
PENGANTAR BAB
Aplikasi web adalah ujung tombak bisnis digital modern. Dari e-commerce, banking online, hingga layanan pemerintah - semuanya berjalan di atas web. Namun, aplikasi web juga menjadi target serangan paling umum. Menurut OWASP 2024, 94% aplikasi web menggunakan framework yang tidak aman, dan SQL Injection masih menjadi salah satu vulnerability paling berbahaya.
Bab ini akan membawa Anda dari konsep dasar keamanan web hingga pemahaman mendalam tentang OWASP Top 10 - daftar vulnerability web paling kritis. Anda akan belajar bagaimana serangan seperti SQL Injection, XSS, dan Broken Access Control bekerja, serta cara mencegahnya.
Setelah bab ini, Anda akan mampu mengembangkan dan mengaudit aplikasi web dengan pendekatan security-first.
OWASP 2024
IBM 2023
Acunetix 2024
OWASP Top 10 2021
- Memahami konsep keamanan aplikasi web
- Mengamankan komunikasi HTTP/HTTPS
- Mengimplementasikan authentication & authorization
- Mengelola session dan cookie dengan aman
- Melakukan input validation yang efektif
- Memahami OWASP Top 10 vulnerabilities
- Mencegah SQL Injection dan XSS
- Menerapkan secure web development practices
KONSEP WEB SECURITY
Definisi
"Web application security is the process of protecting web applications from threats and vulnerabilities by implementing security measures throughout the software development lifecycle."
Arsitektur Aplikasi Web
CIA Triad dalam Web Security
| ASPEK | IMPLEMENTASI DI WEB | CONTOH SERANGAN |
|---|---|---|
| Confidentiality | Enkripsi data, access control | SQL Injection, session hijacking |
| Integrity | Input validation, checksums | XSS, CSRF, data tampering |
| Availability | Load balancing, DDoS protection | DDoS, resource exhaustion |
Ancaman Utama Aplikasi Web
SQL INJECTION
Injeksi query SQL berbahaya
XSS
Injeksi script berbahaya
BROKEN AUTH
BROKEN ACCESS CONTROL
MISCONFIGURATION
CSRF
- Client (browser) = pelanggan yang datang
- Web server = pelayan yang menerima pesanan
- App server = koki yang memasak
- Database = gudang bahan makanan
- SQL Injection = pelanggan memberi instruksi berbahaya ke koki
- XSS = pelanggan meninggalkan catatan berbahaya untuk pelanggan lain
- OWASP - Web Application Security Guide
- NIST SP 800-95 - Guide to Secure Web Services
- W3C - Web Security Specifications
HTTP & HTTPS
HTTP vs HTTPS
| ASPEK | HTTP | HTTPS |
|---|---|---|
| Port | 80 | 443 |
| Enkripsi | Tidak ada (plaintext) | TLS/SSL (encrypted) |
| Keamanan | Data bisa disadap | Data terenkripsi end-to-end |
| Indikator | Tidak ada gembok | Gembok di browser |
| SEO | Ranking lebih rendah | Ranking lebih tinggi |
TLS/SSL Handshake
TLS Handshake Process # 1. Client Hello Client -> Server: Supported cipher suites, TLS version # 2. Server Hello Server -> Client: Selected cipher suite, certificate # 3. Certificate Verification Client verifies server certificate (CA signature, validity) # 4. Key Exchange Client & Server negotiate shared secret key # 5. Encrypted Communication Client <-> Server: All data encrypted with shared key # Contoh cipher suite modern: TLS_AES_256_GCM_SHA384 TLS_CHACHA20_POLY1305_SHA256
SSL/TLS Certificate
| JENIS | VALIDASI | USE CASE |
|---|---|---|
| Domain Validated (DV) | Domain ownership only | Blog, personal site |
| Organization Validated (OV) | Domain + organization | Business websites |
| Extended Validation (EV) | Extended verification | Banking, e-commerce |
Praktik: SSL/TLS Configuration
Nginx - Secure TLS Configuration # /etc/nginx/nginx.conf server { listen 443 ssl http2; server_name example.com; # Certificate ssl_certificate /etc/ssl/certs/example.com.crt; ssl_certificate_key /etc/ssl/private/example.com.key; # Modern TLS configuration ssl_protocols TLSv1.2 TLSv1.3; ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384; ssl_prefer_server_ciphers off; # HSTS (HTTP Strict Transport Security) add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; # OCSP Stapling ssl_stapling on; ssl_stapling_verify on; # Session settings ssl_session_cache shared:SSL:10m; ssl_session_timeout 10m; }
- HTTP = kartu pos - semua orang bisa baca
- HTTPS = amplop tertutup - hanya penerima yang bisa buka
- TLS certificate = segel resmi yang membuktikan amplop asli
- Encryption = isi amplop yang tidak bisa dibaca tanpa kunci
- Mozilla - SSL Configuration Generator (ssl-config.mozilla.org)
- Let's Encrypt - Free SSL Certificates
- RFC 8446 - TLS 1.3 Specification
AUTHENTICATION & AUTHORIZATION
Definisi
| KONSEP | DEFINISI | Pertanyaan |
|---|---|---|
| Authentication (AuthN) | Verifikasi identitas user | "Siapa Anda?" |
| Authorization (AuthZ) | Verifikasi hak akses | "Apa yang boleh Anda lakukan?" |
Authentication Methods
PASSWORD
Sesuatu yang Anda tahu
MFA/2FA
Multi-factor authentication
BIOMETRIC
Sesuatu yang Anda adalah
CERTIFICATE
Digital certificate
QR CODE
Scan to authenticate
OAUTH/SSO
Third-party auth
Authorization Models
| MODEL | DESKRIPSI | USE CASE |
|---|---|---|
| RBAC (Role-Based) | Akses berdasarkan role | Admin, User, Guest |
| ABAC (Attribute-Based) | Akses berdasarkan atribut | Time, location, department |
| ACL (Access Control List) | Daftar akses per resource | File permissions |
| PBAC (Policy-Based) | Akses berdasarkan policy | Complex business rules |
Praktik: Secure Authentication (Node.js)
Node.js - Secure Authentication const bcrypt = require('bcrypt'); const jwt = require('jsonwebtoken'); // Password hashing async function hashPassword(password) { const saltRounds = 12; return await bcrypt.hash(password, saltRounds); } // Password verification async function verifyPassword(password, hash) { return await bcrypt.compare(password, hash); } // Login endpoint app.post('/login', async (req, res) => { const { email, password } = req.body; // Find user const user = await User.findOne({ email }); if (!user) { return res.status(401).json({ error: 'Invalid credentials' }); } // Verify password const valid = await verifyPassword(password, user.passwordHash); if (!valid) { return res.status(401).json({ error: 'Invalid credentials' }); } // Generate JWT const token = jwt.sign( { userId: user.id, role: user.role }, process.env.JWT_SECRET, { expiresIn: '1h' } ); res.json({ token }); }); // Protected route middleware function authenticateToken(req, res, next) { const token = req.headers['authorization']; if (!token) return res.sendStatus(401); jwt.verify(token, process.env.JWT_SECRET, (err, user) => { if (err) return res.sendStatus(403); req.user = user; next(); }); }
- Authentication = menunjukkan ID card di resepsionis
- Authorization = ID card hanya bisa buka ruangan tertentu
- Password = PIN untuk ID card
- MFA = ID card + sidik jari
- Role = departemen (HR, IT, Finance)
- NIST SP 800-63B - Digital Identity Guidelines
- OWASP - Authentication Cheat Sheet
- OWASP - Authorization Cheat Sheet
SESSION & COOKIE
Konsep Session
| KONSEP | DESKRIPSI |
|---|---|
| Session | Periode interaksi user dengan aplikasi |
| Session ID | Identifier unik untuk session |
| Session Storage | Server-side storage untuk session data |
Cookie Security
| ATTRIBUTE | FUNGSI | REKOMENDASI |
|---|---|---|
| Secure | Cookie hanya dikirim via HTTPS | WAJIB untuk session cookies |
| HttpOnly | Cookie tidak bisa diakses via JavaScript | WAJIB untuk session cookies |
| SameSite | Mencegah CSRF | Strict atau Lax |
| Expires/Max-Age | Masa berlaku cookie | Sesuai kebutuhan |
| Domain | Domain yang bisa akses cookie | Spesifik, jangan wildcard |
| Path | Path yang bisa akses cookie | Spesifik |
Praktik: Secure Session Management
Node.js/Express - Secure Session const session = require('express-session'); app.use(session({ // Secret key untuk sign session ID secret: process.env.SESSION_SECRET, // Regenerate session ID setelah login resave: false, saveUninitialized: false, // Cookie settings cookie: { secure: true, // HTTPS only httpOnly: true, // No JavaScript access sameSite: 'strict', // CSRF protection maxAge: 3600000 // 1 hour }, // Session store (production) store: new RedisStore({ client: redisClient }) })); // Regenerate session after login app.post('/login', (req, res) => { req.session.regenerate((err) => { if (err) return res.status(500).send('Error'); req.session.userId = user.id; res.redirect('/dashboard'); }); }); // Destroy session on logout app.post('/logout', (req, res) => { req.session.destroy((err) => { res.redirect('/'); }); });
Session Security Best Practices
- Use strong session IDs - minimal 128-bit entropy
- Regenerate session ID setelah login/logout
- Set secure cookie flags - Secure, HttpOnly, SameSite
- Implement session timeout - idle dan absolute timeout
- Store sessions server-side - jangan di client
- Validate session di setiap request
- Use HTTPS untuk semua komunikasi
- Implement concurrent session control
- Session ID = nomor tiket
- Session data = data di balik tiket (kursi, film)
- Cookie = tiket fisik yang Anda pegang
- Session timeout = tiket hanya berlaku untuk film tertentu
- Session regeneration = tukar tiket lama dengan tiket baru
- OWASP - Session Management Cheat Sheet
- RFC 6265 - HTTP State Management Mechanism
- OWASP - Cookie Security
INPUT VALIDATION
Konsep Input Validation
Input validation adalah proses memastikan data yang masuk ke aplikasi valid, aman, dan sesuai ekspektasi. Ini adalah pertahanan pertama terhadap banyak serangan web.
Jenis Validasi
| JENIS | DESKRIPSI | CONTOH |
|---|---|---|
| Type checking | Validasi tipe data | Number, string, boolean |
| Length checking | Validasi panjang data | Min/max length |
| Range checking | Validasi range nilai | Age: 1-120 |
| Format checking | Validasi format | Email, phone, date |
| Whitelist validation | Hanya terima nilai yang diizinkan | Status: active/inactive |
Praktik: Input Validation (Node.js)
Node.js - Input Validation const Joi = require('joi'); // Define validation schema const userSchema = Joi.object({ username: Joi.string() .alphanum() .min(3) .max(30) .required(), email: Joi.string() .email() .required(), password: Joi.string() .pattern(new RegExp('^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)[a-zA-Z\\d]{8,}$')) .required(), age: Joi.number() .integer() .min(18) .max(120) }); // Validate input app.post('/register', (req, res) => { const { error, value } = userSchema.validate(req.body); if (error) { return res.status(400).json({ error: 'Validation failed', details: error.details }); } // Input is valid, proceed const { username, email, password, age } = value; // ... create user }); // Sanitize HTML input const sanitizeHtml = require('sanitize-html'); const dirty = '<script>alert("xss")</script><p>Hello</p>'; const clean = sanitizeHtml(dirty, { allowedTags: [ 'p', 'b', 'i', 'em', 'strong' ], allowedAttributes: {} }); // Result: '<p>Hello</p>'
Best Practices
- Validate on server-side - client-side validation bisa di-bypass
- Use whitelist - terima hanya yang diketahui aman
- Reject invalid input - jangan coba perbaiki
- Validate all input - URL, headers, cookies, body
- Use established libraries - jangan buat validator sendiri
- Sanitize output - escape HTML special characters
- Use parameterized queries - untuk database queries
- Input validation = satpam yang memeriksa setiap tamu
- Whitelist = daftar tamu yang diizinkan
- Blacklist = daftar tamu yang dilarang
- Type checking = memeriksa apakah tamu membawa ID yang valid
- Length checking = memeriksa apakah paket tidak terlalu besar
- OWASP - Input Validation Cheat Sheet
- OWASP - DOM-based XSS Prevention Cheat Sheet
- Joi - Validation Library Documentation
OWASP TOP 10
Apa itu OWASP Top 10?
OWASP Top 10 adalah daftar kesadaran standar untuk risiko keamanan aplikasi web paling kritis. Daftar ini diperbarui secara berkala berdasarkan data dari ratusan organisasi.
OWASP Top 10 (2021)
| # | VULNERABILITY | DESKRIPSI | DAMPAK |
|---|---|---|---|
| A01 | Broken Access Control | Restriksi pada apa yang boleh dilakukan user tidak ditegakkan | Critical |
| A02 | Cryptographic Failures | Kegagalan terkait kriptografi | Critical |
| A03 | Injection | SQL, NoSQL, OS, LDAP injection | High |
| A04 | Insecure Design | Kekurangan dalam desain arsitektur | High |
| A05 | Security Misconfiguration | Konfigurasi keamanan yang tidak aman | High |
| A06 | Vulnerable Components | Komponen dengan kerentanan yang diketahui | Medium |
| A07 | Identification Failures | Kegagalan autentikasi dan identifikasi | Medium |
| A08 | Software & Data Integrity | Kegagalan memverifikasi integritas | Medium |
| A09 | Logging & Monitoring | Kurangnya logging dan monitoring | Low |
| A10 | SSRF | Server-Side Request Forgery | Low |
Mencegah OWASP Top 10
- A01: Implement access control checks, deny by default
- A02: Use strong encryption, proper key management
- A03: Use parameterized queries, input validation
- A04: Threat modeling, secure design patterns
- A05: Hardening guides, automated verification
- A06: Software composition analysis, patch management
- A07: MFA, secure password storage, rate limiting
- A08: Code signing, dependency verification
- A09: Comprehensive logging, alerting
- A10: Validate URLs, block internal URLs
- OWASP - Top 10 2021 (owasp.org/Top10)
- OWASP - Application Security Verification Standard (ASVS)
- OWASP - Testing Guide
SQL INJECTION
Apa itu SQL Injection?
SQL Injection (SQLi) adalah serangan injection yang memungkinkan attacker menyisipkan query SQL berbahaya melalui input aplikasi. Ini bisa memungkinkan attacker untuk membaca, memodifikasi, atau menghapus data di database.
Contoh SQL Injection
SQL Injection Example # Vulnerable code (PHP) $username = $_POST['username']; $query = "SELECT * FROM users WHERE username = '" . $username . "'"; # Normal input: # username = "admin" # Query: SELECT * FROM users WHERE username = 'admin' # Malicious input: # username = "' OR '1'='1" # Query: SELECT * FROM users WHERE username = '' OR '1'='1' # Result: Returns ALL users (condition always true) # More dangerous: # username = "'; DROP TABLE users; --" # Query: SELECT * FROM users WHERE username = ''; DROP TABLE users; --' # Result: Deletes entire users table!
Praktik: Mencegah SQL Injection
Node.js - Preventing SQL Injection # ❌ VULNERABLE - String concatenation const query = `SELECT * FROM users WHERE username = '${username}'`; db.query(query); # ✅ SECURE - Parameterized query const query = 'SELECT * FROM users WHERE username = ?'; db.query(query, [username]); # ✅ SECURE - Using ORM (Sequelize) const user = await User.findOne({ where: { username: username } }); # ✅ SECURE - Using prepared statements (MySQL) const stmt = db.prepare('SELECT * FROM users WHERE username = ?'); const user = stmt.get(username);
Pencegahan SQL Injection
- Use parameterized queries - prepared statements
- Use ORM - Object-Relational Mapping
- Input validation - whitelist allowed characters
- Escape special characters - jika parameterized query tidak memungkinkan
- Least privilege - batasi hak akses database user
- WAF (Web Application Firewall) - deteksi pola SQLi
- Error handling - jangan tampilkan error detail ke user
- Normal order = "Saya ingin nasi goreng"
- SQLi attack = "Saya ingin nasi goreng. Oh ya, tolong bakar seluruh dapur juga"
- Parameterized query = koki hanya menerima pesanan dalam kotak tertutup, tidak bisa membaca instruksi tambahan
Heartland Payment Systems (2008): Attacker menggunakan SQL injection untuk mencuri 130 juta nomor kartu kredit. Kerugian: $110 juta.
Sony Pictures (2011): SQL injection digunakan untuk mencuri data pengguna dari Sony Pictures, termasuk 1 juta data pengguna.
- OWASP - SQL Injection Prevention Cheat Sheet
- OWASP - SQL Injection
- PortSwigger - SQL Injection
CROSS-SITE SCRIPTING (XSS)
Apa itu XSS?
Cross-Site Scripting (XSS) adalah vulnerability yang memungkinkan attacker menyisipkan script berbahaya (biasanya JavaScript) ke halaman web yang dilihat oleh user lain. Script ini berjalan di browser korban.
Jenis XSS
| JENIS | DESKRIPSI | SEVERITY |
|---|---|---|
| Stored XSS | Script disimpan di server (database) | High |
| Reflected XSS | Script dipantulkan dari request | Medium |
| DOM-based XSS | Script dimodifikasi di DOM client-side | Medium |