Anatomi Kebocoran Data di Inertia.js
Inertia.js bekerja dengan menjembatani backend dan frontend tanpa memerlukan endpoint REST/GraphQL terpisah. Namun, mekanisme pengiriman data Inertia sering menjadi sumber kerentanan: seluruh data props diserialisasi menjadi JSON murni dan disematkan langsung ke dalam atribut HTML data-page pada render awal, atau dikirimkan via response header/body XHR pada navigasi berikutnya.
Ketika controller mengirimkan instance model Eloquent mentah secara langsung ke view, seluruh atribut internal yang tidak dilindungi akan terpapar ke sisi klien. Pengguna dapat membaca data ini secara bebas melalui inspect element DevTools atau mengeksekusi script berikut pada konsol browser:
console.log(JSON.parse(document.getElementById('app').dataset.page).props);Atribut sensitif seperti two_factor_secret, stripe_id, password_hash, token verifikasi, hingga Personally Identifiable Information (PII) dapat bocor seketika jika serialisasi tidak dikontrol secara ketat.
Kelemahan Model-Level Serialization
Sebagian developer mengandalkan properti $hidden pada model Eloquent untuk mencegah kebocoran data. Pendekatan ini memiliki sejumlah celah struktural:
- Kerapuhan saat Refactoring: Penambahan kolom baru pada migrasi database berisiko langsung terekspos jika developer lupa memperbarui array
$hidden. - Relasi Eager-Loading: Memanggil relasi seperti
$user->load('orders.transactions')sering kali mengekspos model relasi tanpa konfigurasi penyembunyian atribut yang setara. - Kebutuhan Kontekstual: Atribut yang aman dilihat oleh admin (misalnya riwayat login) bisa menjadi kebocoran data berbahaya jika props yang sama dibagikan ke pengguna reguler.
Perbandingan Kode Controller: Unsafe vs Safe
Hindari passing model langsung ke helper Inertia::render(). Terapkan pemetaan eksplisit sebelum payload dikirim ke frontend.
Contoh Controller Tidak Aman (Vulnerable)
namespace App\Http\Controllers;
use App\Models\User;
use Inertia\Inertia;
use Inertia\Response;
class UserController extends Controller
{
public function show(User $user): Response
{
// BAHAYA: Mengirimkan seluruh kolom tabel users ke DOM
return Inertia::render('Users/Show', [
'user' => $user,
]);
}
}Contoh Controller Aman (Secure)
namespace App\Http\Controllers;
use App\Http\Resources\UserData;
use App\Models\User;
use Inertia\Inertia;
use Inertia\Response;
class UserController extends Controller
{
public function show(User $user): Response
{
// AMAN: Transformasi ketat via DTO / Resource
return Inertia::render('Users/Show', [
'user' => UserData::fromModel($user),
]);
}
}Implementasi Data Transfer Object (DTO) Ringkas
Menggunakan DTO berbasis native PHP 8.2+ memberikan jaminan tipe data sekaligus membatasi data props secara deterministik.
namespace App\Http\Resources;
use App\Models\User;
readonly class UserData
{
public function __construct(
public int $id,
public string $name,
public string $email,
public string $avatarUrl,
) {}
public static function fromModel(User $user): self
{
return new self(
id: $user->id,
name: $user->name,
email: $user->email,
avatarUrl: $user->profile_photo_url ?? '',
);
}
}Alternatif: Anda juga dapat menggunakan
JsonResourcebawaan Laravel. Pastikan metodetoArray()mendefinisikan array asosiatif secara eksplisit, bukan memanggilparent::toArray($request).
Audit Middleware HandleInertiaRequests
Middleware HandleInertiaRequests bertugas mendistribusikan data global (shared props) ke seluruh halaman aplikasi. Kesalahan umum di file ini adalah membagikan objek auth user mentah atau konfigurasi lingkungan.
namespace App\Http\Middleware;
use Illuminate\Http\Request;
use Inertia\Middleware;
class HandleInertiaRequests extends Middleware
{
public function share(Request $request): array
{
return array_merge(parent::share($request), [
'auth' => [
'user' => $request->user() ? [
'id' => $request->user()->id,
'name' => $request->user()->name,
'email' => $request->user()->email,
'role' => $request->user()->role,
] : null,
],
// HINDARI: Menaruh token integrasi atau secret key di sini
// 'services' => config('services.stripe.secret'),
]);
}
}Otomasi Verifikasi Menggunakan Pest PHP
Uji secara otomatis bahwa response Inertia tidak mengandung properti sensitif menggunakan assertion bawaan Inertia testing.
use App\Models\User;
use Inertia\Testing\AssertableInertia as Assert;
test('halaman user show tidak mengekspos atribut sensitif', function () {
$user = User::factory()->create([
'two_factor_secret' => 'encrypted-secret-string',
'remember_token' => 'random-token',
]);
$this->actingAs($user)
->get(route('users.show', $user))
->assertOk()
->assertInertia(fn (Assert $page) => $page
->component('Users/Show')
->has('user.id')
->has('user.name')
->has('user.email')
->missing('user.password')
->missing('user.two_factor_secret')
->missing('user.remember_token')
);
});Pengujian ini memastikan jika ada developer lain yang mencoba mengembalikan model mentah secara tidak sengaja, build pipeline (CI/CD) akan langsung gagal sebelum perubahan masuk ke production.
Komentar
0 komentar
Masuk ke akun kamu untuk ikut berkomentar.
Belum ada komentar
Jadilah yang pertama ikut berdiskusi!