Celah keamanan parser differential muncul saat dua komponen arsitektur—seperti API Gateway dan microservice backend—mengurai format pesan yang sama dengan logika atau tata bahasa (grammar) yang berbeda. Ketidakkonsistenan interpretasi ini memungkinkan penyerang menyelundupkan payload berbahaya yang lolos dari filter gateway namun dieksekusi oleh backend.
Prinsip Language-theoretic Security (LangSec), sebagaimana ditegaskan dalam literatur seperti 'Seventy Years of Parsing' oleh Len Sassaman dkk., memandang kerentanan input bukan sekadar kesalahan validasi logika, melainkan kegagalan mendasar dalam mendefinisikan dan membatasi grammar input. Penanganan data sebelum tata bahasanya tervalidasi secara deterministik membuka ruang eksploitasi tersembunyi.
Anatomi Parser Differential: Kasus Ambiguity JSON dan HTTP
Spesifikasi protokol seperti JSON (RFC 8259) dan HTTP (RFC 9112) menyisakan ruang ambiguitas bagi pengembang parser. Sebagai contoh, RFC JSON tidak melarang kunci duplikat secara eksplisit, melainkan menyerahkan perilakunya ke parser implementor.
1. JSON Duplicate Key Attack (Auth Bypass)
Perhatikan contoh payload JSON berikut:
{
"role": "user",
"role": "admin"
}Jika API Gateway menggunakan parser A (yang membaca kunci pertama) untuk memeriksa hak akses, gateway melihat "role": "user" dan mengizinkan request lewat. Namun, jika microservice backend menggunakan parser B (yang menimpa nilai dengan kunci terakhir), backend memproses request dengan hak "role": "admin". Akibatnya, mekanisme RBAC (Role-Based Access Control) terlewati tanpa disadari.
2. Header Smuggling dan SSRF Melalui Ambigu Mutasi HTTP
Perbedaan perlakuan karakter whitespace atau carriage return (CRLF) pada HTTP headers antara reverse proxy dan backend web server memicu HTTP request smuggling. Penyerang menyisipkan header ganda atau encoding Transfer-Encoding: chunked yang diinterpretasikan berbeda, memungkinkan request tersembunyi diteruskan ke endpoint internal privat (SSRF).
Prinsip LangSec dalam Menangani Input
LangSec menetapkan bahwa setiap format pertukaran data adalah sebuah bahasa formal. Untuk mengamankan sistem terdistribusi:
- Input Handling sebagai Recognizer: Parsing harus bertindak sebagai recognizer deterministik yang menolak input jika grammar tidak cocok secara tepat, bukan mencoba 'membersihkan' (sanitize) input ambigu.
- Batas Kompleksitas: Bahasa format pertukaran harus sesederhana mungkin (idealnya regular atau deterministic context-free) dan menghindari format rekursif berlebih yang rawan Denial-of-Service atau parser drift.
- Tolak Ambigu (Strict Non-Tolerant): Parser harus gagal secara eksplisit saat mendeteksi duplikasi kunci, whitespace non-standar, atau format data ganda.
Strategi Mitigasi Teknis di API Gateway
Mencegah parser differential memerlukan penerapan pola deterministik sebelum data didistribusikan ke jaringan internal microservice.
1. Canonical Parsing dan Re-serialization
Gateway tidak boleh hanya membaca payload secara pasif lalu meneruskan buffer mentah (raw buffer) ke backend. Gateway harus mengurai, memvalidasi, menormalkan (canonicalize), lalu melakukan serialisasi ulang (re-serialize) payload sebelum diteruskan.
Contoh middleware pada gateway berbasis Go untuk mendeteksi kunci duplikat dan menolak representasi ambigu:
package main
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
)
func StrictJSONValidationMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.Header.Get("Content-Type") != "application/json" {
next.ServeHTTP(w, r)
return
}
body, err := io.ReadAll(r.Body)
if err != nil {
http.Error(w, "Gagal membaca request", http.StatusBadRequest)
return
}
// Deteksi duplicate keys dengan streaming decoder
dec := json.NewDecoder(bytes.NewReader(body))
seenKeys := make(map[string]bool)
t, err := dec.Token()
if err != nil || t != json.Delim('{') {
http.Error(w, "Format JSON tidak valid", http.StatusBadRequest)
return
}
for dec.More() {
k, err := dec.Token()
if err != nil {
http.Error(w, "Error token JSON", http.StatusBadRequest)
return
}
keyStr := fmt.Sprintf("%v", k)
if seenKeys[keyStr] {
http.Error(w, "Ambiguous payload: duplicate key terdeteksi", http.StatusBadRequest)
return
}
seenKeys[keyStr] = true
// Lewati nilai terkait untuk melanjutkan scanning kunci root
var val interface{}
if err := dec.Decode(&val); err != nil {
http.Error(w, "Nilai payload tidak valid", http.StatusBadRequest)
return
}
}
// Setel ulang body dengan buffer yang telah divalidasi
r.Body = io.NopCloser(bytes.NewReader(body))
next.ServeHTTP(w, r)
})
}2. Single-Source Grammar Validation (Schema Registry)
Gunakan satu definisi skema terpusat, misalnya JSON Schema atau Protobuf schema, yang dibagikan antara gateway dan backend. Kontrak request deterministik harus diterapkan tanpa deviasi implementasi parser library:
- Tentukan
additionalProperties: falsedalam skema JSON untuk mencegah penyelundupan atribut tak terdaftar. - Pertimbangkan validasi skema berbasis format binary seperti gRPC/Protocol Buffers di layer gateway-to-backend untuk meniadakan ambiguitas text parsing pada perimeter internal.
Trade-offs dan Pertimbangan Kinerja
Menerapkan re-serialization dan parsing ketat di edge gateway memiliki kompromi:
- Latensi Ekstra: Membaca seluruh stream body, memparsing AST/token, dan menyusun ulang JSON menambah alokasi memori serta latensi CPU (terutama untuk payload besar di atas 1MB).
- Throughput Degradation: Gateway yang sebelumnya bersifat lightweight reverse proxy berubah menjadi compute-intensive recognizer.
- Solusi Efisiensi: Jalankan validasi skema ketat hanya pada perimeter publik yang menangani otentikasi dan operasi state-changing (POST, PUT, PATCH), serta teruskan stream mentah untuk traffic terenkripsi antar-internal service tepercaya.
Komentar
0 komentar
Masuk ke akun kamu untuk ikut berkomentar.
Belum ada komentar
Jadilah yang pertama ikut berdiskusi!