Web Application Security Fundamentals #07: Input Validation & Sanitization
Memahami input validation dengan whitelist approach, server-side validation, output sanitization, dan secure file upload handling.
Input validation adalah first line of defense untuk mencegah injection attacks. Filosofinya sederhana: never trust user input. Setiap data dari user, query parameter, file upload, atau API request harus divalidasi dan disanitasi.
Tujuan Pembelajaran
- Membedakan whitelist vs blacklist validation
- Implement server-side input validation
- Sanitize output sesuai context (HTML, URL, SQL, JS)
- Handle file uploads dengan aman
- Test input validation dengan payload fuzzing
Input Validation Best Practices
1. Whitelist > Blacklist
# ❌ BLACKLIST (buruk)
def validate_email(email):
forbidden = ['<', '>', '"', "'", ';', '--', 'DROP', 'DELETE']
for word in forbidden:
if word in email:
return False
return True
# ❌ Mudah dibypass: "DR<OP", encoded versions
# ✅ WHITELIST (baik)
import re
def validate_email(email):
pattern = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'
return re.match(pattern, email) is not None
2. Server-Side Validation (tidak client-only)
// ❌ VULNERABLE - Client-side only
function validateForm() {
const email = document.getElementById('email').value;
if (email.includes('@')) {
sendToServer(email); // Attacker bypass dengan raw request
}
}
// ✅ SECURE - Server-side validation
app.post('/subscribe', (req, res) => {
const email = req.body.email;
// Validate
if (!email || email.length > 100) {
return res.status(400).json({ error: 'Invalid email' });
}
if (!isValidEmail(email)) {
return res.status(400).json({ error: 'Invalid email format' });
}
// Process
subscribe(email);
res.json({ success: true });
});
3. Sanitize Output
// ❌ VULNERABLE
document.getElementById('result').innerHTML = userInput;
// ✅ SAFE - HTML context
document.getElementById('result').textContent = userInput;
// ✅ SAFE - Encode untuk HTML context
function htmlEncode(str) {
return str.replace(/&/g, '&')
.replace(/</g, '<')
.replace(/>/g, '>')
.replace(/"/g, '"')
.replace(/'/g, ''');
}
// ✅ SAFE - URL context
const url = 'https://example.com/search?q=' + encodeURIComponent(userInput);
// ✅ SAFE - JavaScript context
const data = JSON.stringify(userInput);
File Upload Security
Validation
# ❌ VULNERABLE
@app.route('/upload', methods=['POST'])
def upload():
file = request.files['file']
file.save(f'/uploads/{file.filename}') # Attacker upload shell.php!
return 'OK'
# ✅ SECURE
ALLOWED_EXTENSIONS = {'jpg', 'jpeg', 'png', 'pdf'}
MAX_FILE_SIZE = 5 * 1024 * 1024 # 5MB
@app.route('/upload', methods=['POST'])
def upload():
file = request.files['file']
# Check size
if len(file.read()) > MAX_FILE_SIZE:
file.seek(0)
return 'File too large', 400
file.seek(0)
# Check extension
ext = file.filename.split('.')[-1].lower()
if ext not in ALLOWED_EXTENSIONS:
return 'Invalid file type', 400
# Check MIME type
import magic
mime = magic.from_buffer(file.read(), mime=True)
if not mime.startswith(('image/', 'application/pdf')):
return 'Invalid file type', 400
file.seek(0)
# Rename file (prevent traversal)
import uuid
filename = f'{uuid.uuid4()}.{ext}'
file.save(f'/uploads/{filename}')
return {'filename': filename}
Input Validation Checklist
- [ ] Length check (min/max)
- [ ] Type check (string/number/email/URL)
- [ ] Format check (regex pattern)
- [ ] Range check (value between min-max)
- [ ] Whitelist characters (if applicable)
- [ ] Encoding check (UTF-8, prevent null bytes)
- [ ] No SQL/command injection patterns
- [ ] No XXE payloads (if XML)
- [ ] File upload: extension, MIME type, size, content
- [ ] API key format validation
Testing Input Validation
# Test 1: Length boundary
curl "https://api.example.com/search?q=$(python3 -c 'print("A"*10000)')"
# Test 2: Special characters
curl "https://api.example.com/search?q=test' OR '1'='1"
curl "https://api.example.com/search?q=test<img src=x onerror=alert(1)>"
# Test 3: Null bytes
curl "https://api.example.com/search?q=test%00admin"
# Test 4: Encoding bypass
curl "https://api.example.com/search?q=test%2527%20OR%20%25271%2527%253D%25271"
# Test 5: File upload
curl -F "file=@shell.php" https://api.example.com/upload
curl -F "file=@../../../etc/passwd" https://api.example.com/upload
Kesimpulan
Input validation adalah investasi kecil dengan ROI besar. Fail-first approach (default reject, explicit allow) membuat control yang robust.
Modul berikutnya (#08) membahas Authentication & Session Management.
Next: #08 - Authentication & Session Management
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...
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,...
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...