Episode ini masuk ke Fase 4 tentang keamanan runtime: cara memuat bundel JavaScript Hermes dengan aman, menghindari remote code execution dan eval yang tidak aman, serta mitigasi praktis untuk aplikasi mobile dan edge runtime.

Di episode 11 kita menutup Fase 3 dengan menata konfigurasi Hermes supaya build reproducible, tervalidasi di CI, dan terintegrasi dengan release pipeline. Sekarang kita memasuki Fase 4: Networking & Security. Kalau performa itu soal kecepatan, keamanan itu soal apa yang terjadi kalau aplikasi kalian sudah sampai di tangan orang yang tidak berniat baik.
Episode 12 berfokus pada secure runtime practices: bagaimana bundel JavaScript Hermes kalian dimuat dengan aman, bagaimana menghindari remote code execution dan eval yang tidak aman, lalu contoh mitigasi nyata untuk aplikasi mobile dan edge runtime. Roadmap-nya: model ancaman, secure loading, menghindari RCE, mitigasi di mobile, lalu mitigasi di edge.
Hermes mengeksekusi bundel yang dikompilasi menjadi bytecode .hbc. Penting dipahami sejak awal: bytecode Hermes bukan enkripsi. File .hbc bisa dibongkar kembali menjadi disassembly menggunakan tool hbcdump, dan struktur internalnya sudah didokumentasikan. Yang melindungi aplikasi bukan "kerahasiaan" bytecode, melainkan integritas dan kontrol atas apa yang dieksekusi.
Model ancaman khas aplikasi mobile:
Info
Aturan emasnya: apa pun yang kalian kontrol (bundel, konfigurasi, native code) harus selalu diasumsikan bisa dibaca dan dianalisis penyerang. Keamanan datang dari verifikasi, bukan dari menyembunyikan kode.
Cara paling aman memuat bundel Hermes adalah memasangnya di dalam aset aplikasi saat build, bukan mengunduhnya dari server saat runtime. Di React Native, file index.android.bundle (yang di release build adalah bytecode .hbc) sudah otomatis dikemas ke dalam APK. Selama kalian tidak mengganti mekanisme ini, bundel ikut ditandatangani oleh tanda tangan aplikasi di toko aplikasi.
Kalau aplikasi kalian terpaksa mengambil bundel dari jaringan — misalnya untuk update over-the-air — jangan pernah percaya hasil unduhan mentah-mentah. Verifikasi terlebih dahulu dengan hash yang diketahui:
import { checkBundleSignature } from "./crypto-utils";
const EXPECTED_SHA256 = "ab3f...0c9d";
async function loadRemoteBundle(url) {
const bundle = await fetch(url).then((res) => res.arrayBuffer());
const digest = await checkBundleSignature(bundle);
if (digest !== EXPECTED_SHA256) {
throw new Error("Integritas bundel gagal diverifikasi");
}
return bundle;
}Hash statis seperti di atas hanya masuk akal untuk rilis yang dijadwalkan. Untuk update yang lebih sering, ganti mekanismenya dengan tanda tangan kriptografis: kunci publik disematkan di aplikasi, bundel ditandatangani kunci privat di sisi server, dan aplikasi memverifikasi tanda tangan tersebut. Selalu kombinasikan dengan HTTPS dan, bila memungkinkan, certificate pinning.
Kabar baiknya: Hermes sejak awal tidak mendukung local eval. Memanggil eval di Hermes tidak akan memberi akses ke variabel lokal maupun mendefinisikan variabel baru di luar — perilakunya menyimpang dari spesifikasi dan di beberapa kasus langsung melempar error. Ini bukan bug, tapi keputusan desain yang sekaligus memperkecil permukaan serangan: tidak ada jalur eksekusi kode dinamis gratis.
Meski begitu, kalian tetap bisa menembak kaki sendiri. Pola berbahaya yang wajib dihindari: new Function, template string yang mengeksekusi kode, dan yang paling klasik — fetch lalu eval. Ini contoh buruknya:
const config = await fetch("https://api.example.com/feature").then((r) => r.text());
const feature = new Function(config);
feature();Dan ini pengganti yang aman — data tetap data, tidak pernah jadi kode:
const payload = await fetch("https://api.example.com/feature").then((r) => r.json());
const feature = {
enabled: payload.enabled === true,
label: String(payload.label ?? "fitur baru"),
};const code = `return ${userInput};`;
const result = new Function(code)();Perhatikan bahwa JSON.parse bukan pengganti seratus persen untuk semua kasus eval — ia hanya mem-parsing struktur data. Itu justru maksudnya: kalau yang kalian butuhkan hanyalah data, gunakan format data. Kalau kalian butuh logika, tulis logika tersebut sebagai fungsi sungguhan yang menerima input, bukan sebagai string yang dikompilasi saat itu juga.
Warning
Hati-hati juga dengan helper yang membungkus new Function untuk "menyusun query" atau "template engine". Di Hermes helper semacam itu sering pecah di device karena keterbatasan eval lokal — selain berbahaya secara keamanan, mereka juga tidak portabel.
Berikut rangkaian minimum yang harus selalu aktif untuk build release mobile:
evalString yang disediakan beberapa modul debugging).Flag kompiler di android/app/build.gradle juga bisa dikunci agar konsisten antar developer:
react {
hermesFlags = ["-O", "-output-source-map"]
}Dengan -output-source-map, stack trace produksi bisa dipetakan balik ke sumber asli — tapi pastikan file .map hasilnya disimpan di CI untuk digunakan tool observability, bukan dibundle.
Di edge runtime (serverless, Cloudflare Workers, atau embedded Hermes di Node.js), prinsipnya sama, tapi ancamannya bergeser: kini yang tidak dipercaya adalah input request, bukan bundel. Pikiran pertama yang harus muncul: kode yang dieksekusi adalah kode milik kalian, sedangkan semua input dari luar adalah data. Jangan pernah membangun jalur di mana input bisa menjadi instruksi:
import { z } from "zod";
const schema = z.object({
command: z.enum(["list", "detail", "refresh"]),
id: z.string().max(36),
});
export async function handler(req: Request) {
const parsed = schema.safeParse(await req.json());
if (!parsed.success) return new Response("invalid", { status: 400 });
return runKnownCommand(parsed.data);
}Dengan z.enum, nilai command hanya boleh dari daftar yang kita kenal. Tidak ada jalur di mana input asing menjadi nama fungsi yang dipanggil secara dinamis — polanya tetap memetakan string ke fungsi yang sudah terdaftar, bukan mengeksekusi string.
Keamanan runtime Hermes bukan tentang menyembunyikan bytecode, melainkan mengendalikan apa yang bisa dieksekusi dan memastikan apa yang dieksekusi itu memang milik kalian. Dengan bundel yang disematkan dan diverifikasi, larangan terhadap pola eval dinamis, serta kunci build yang ketat, permukaan serangan menyusut drastis.
Inti yang harus dibawa pulang:
eval, new Function, dan pola fetch-lalu-eksekusi di semua kode aplikasi.Di episode 13, kita lanjut dengan Hermes and JIT / AOT Security Considerations: bagaimana pilihan AOT mempengaruhi profil keamanan, apa itu signed bundles dan content integrity, serta cara mengintegrasikan hardening dan privacy ke runtime. Sampai jumpa!