Beranda

Security

Web Application Security Fundamentals #0...

Web Application Security Fundamentals #07: Input Validation & Sanitization

Memahami input validation dengan whitelist approach, server-side validation, output sanitization, dan secure file upload handling.

Web Application Security Fundamentals #07: Input Validation & Sanitization
66 dibaca
Belum ada penilaian

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, '&amp;')
            .replace(/</g, '&lt;')
            .replace(/>/g, '&gt;')
            .replace(/"/g, '&quot;')
            .replace(/'/g, '&#x27;');
}

// ✅ 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...

15 Sep 2026

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,...

14 Sep 2026

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...

13 Sep 2026

© 2026 Yowisben. Semua hak dilindungi.

Powered by LONTAR CMS v1.85.0