# Mengamankan Next.js Server Actions: Auth, IDOR & Validasi Zod

> Setiap fungsi use server adalah endpoint POST publik. Cara saya memperkuat Next.js Server Actions dengan auth per-aksi, cek kepemilikan, validasi Zod, dan rate limiting.

URL: https://www.matthewswong.com/id/blog/nextjs-server-actions-security/

- Author: Matthews Wong (https://www.matthewswong.com/id/about/)
- Published: 2026-08-01
- Updated: 2026-08-01
- Category: Web Dev

> **Key takeaway:** Setiap Next.js Server Action yang ditandai use server dikompilasi menjadi endpoint POST publik yang bisa dipanggil siapa saja secara langsung, jadi tipe TypeScript dan validasi sisi klien tidak melindungi apa pun. Tiap aksi butuh autentikasi sendiri, otorisasi kepemilikan sumber daya untuk mencegah IDOR, validasi Zod sisi server di batas masukan, serta rate limiting pada operasi mahal.

Pertama kali saya merilis Server Action, rasanya seperti memanggil fungsi lokal. Saya mengimpornya, menyerahkannya ke form action, dan mutasinya langsung jalan. Ergonomi itulah jebakannya. Server Action bukan fungsi privat yang hanya bisa dijangkau UI Anda. Ia dikompilasi menjadi endpoint HTTP nyata, dan dokumentasi Next.js menyatakannya dengan gamblang: begitu sebuah aksi dibuat dan diekspor, ia dapat dijangkau lewat permintaan POST langsung, bukan hanya melalui UI aplikasi Anda.

Fakta tunggal itu mengubah seluruh model keamanan. Penyerang tidak pernah menyentuh komponen React Anda. Mereka membuka tab jaringan, membaca ID aksi, dan mengulang POST dengan payload apa pun yang mereka mau. Tanda tangan TypeScript Anda, tombol submit yang dinonaktifkan, skema Zod sisi klien, rendering kondisional yang menyembunyikan tombol dari non-admin, semuanya berjalan di browser, dan browser adalah satu tempat yang tidak Anda kendalikan. Tulisan ini adalah cara saya memperkuat setiap aksi yang saya tulis.

## Mengapa use server adalah endpoint publik, bukan panggilan fungsi

Next.js memang menambahkan proteksi nyata. Ia menghasilkan ID aksi yang terenkripsi dan non-deterministik agar klien tidak bisa menebaknya, menghitung ulang ID itu antar-build, dan dead-code elimination membuang aksi yang tidak pernah Anda referensikan sehingga tak pernah menjadi endpoint yang bisa dipanggil. Server Actions juga hanya menerima POST dan membandingkan header Origin dengan header Host, yang memblokir sebagian besar CSRF di browser modern, terlebih dengan cookie SameSite sebagai bawaan.

Tetapi semua itu bukan otorisasi. Dokumentasi menyatakannya jelas: ini mengurangi risiko ketika lapisan auth tidak ada, namun Anda tetap harus memperlakukan Server Actions sebagai dapat dijangkau lewat permintaan POST langsung dan memverifikasi autentikasi serta otorisasi di dalam masing-masing aksi. ID terenkripsi menghentikan penebakan, bukan pengguna yang sudah login mengulang permintaan untuk sumber daya yang bukan miliknya. Batas keamanan adalah tubuh aksi, dan tidak ada satu pun sebelum itu yang boleh dipercaya.

> Model berpikir yang melekat pada saya: perlakukan setiap fungsi use server dengan kecurigaan yang sama seperti rute REST publik. Jika Anda tidak akan mengeksposnya sebagai endpoint API tanpa autentikasi, jangan merilisnya sebagai Server Action tanpa pemeriksaan yang sama. Sintaks panggilan fungsi yang praktis itu adalah fitur UI, bukan fitur keamanan.

## Tiga pemeriksaan yang dibutuhkan setiap aksi di batasnya

Seiring waktu saya menetapkan urutan tetap di bagian atas setiap aksi yang melakukan mutasi. Melewatkan salah satunya meninggalkan celah nyata, dan urutannya penting karena tiap langkah bergantung pada langkah sebelumnya.

- Autentikasi, siapa yang memanggil. Baca ulang sesi di dalam aksi, karena pemeriksaan tingkat halaman atau proxy tidak berlaku untuk Server Action yang didefinisikan di halaman itu. Jika tidak ada sesi valid, lemparkan error sebelum melakukan apa pun.
- Validasi, apakah masukan berbentuk benar. Parse setiap field dengan skema sisi server seperti Zod. Validasi klien hanyalah kenyamanan UX, dan penyerang bisa menyusun permintaan mentah yang melewatinya, jadi parsing harus terjadi di sini.
- Otorisasi dan kepemilikan, bolehkah pengguna ini bertindak atas catatan spesifik ini. Muat baris target dan pastikan ia milik pemanggil. Inilah pemeriksaan yang menghentikan Insecure Direct Object Reference, di mana pengguna valid menukar ID dan menyunting data orang lain.

Berikut pola yang saya andalkan, diadaptasi langsung dari panduan data-security Next.js. Ketiga pemeriksaan berjalan berurutan sebelum satu byte pun ditulis, dan akses basis data didelegasikan ke helper agar aksinya tetap ramping dan mudah diaudit:

Perhatikan pemeriksaan kepemilikan pada baris post.authorId. Autentikasi saja akan dengan senang hati membiarkan pengguna login mana pun menghapus atau menyunting post mana pun berdasarkan ID. Celah itu adalah kerentanan Server Action paling umum yang saya temui saat review, dan ia tak terlihat di sistem tipe karena ID hanyalah sebuah string. Pencarian basis data plus pemeriksaan kesetaraan itulah yang menutupnya.

> Jangan mengandalkan redirect di bagian atas halaman untuk melindungi aksi di dalamnya. Pemeriksaan auth tingkat halaman mengatur UI mana yang dirender. Server Action adalah titik masuk yang sepenuhnya terpisah dan harus memverifikasi ulang pemanggil sendiri. Dokumentasi menyebut pemeriksaan auth di dalam aksi sebagai kritis justru karena alasan ini, dan hal yang sama berlaku untuk pemeriksaan proxy atau middleware, yang bersifat optimistik, bukan jaminan di sumber data.

## Tidak aman versus diperkuat, berdampingan

| Aspek | Aksi tidak aman | Aksi diperkuat |
| --- | --- | --- |
| Autentikasi | Bergantung pada redirect halaman atau tombol tersembunyi | Membaca ulang sesi di dalam tubuh aksi |
| Penanganan masukan | Memercayai formData dan argumen bertipe apa adanya | Mem-parse setiap field dengan Zod safeParse dulu |
| Otorisasi | Bertindak atas ID apa pun yang diberikan pemanggil | Memuat baris dan memeriksa kepemilikan, memblokir IDOR |
| Nilai balik | Mengembalikan catatan basis data mentah | Hanya mengembalikan field yang dibutuhkan UI |
| Kontrol penyalahgunaan | Tanpa pembatasan pada write, email, atau login | Membatasi laju operasi mahal per pengguna |

## CSRF, allowed origins, rate limiting, dan aksi yang ramping

Di luar tiga pemeriksaan inti, beberapa hal tambahan penting. Server Actions sudah membandingkan Origin dengan Host untuk memblokir CSRF, tetapi jika Anda berjalan di belakang reverse proxy tempat host API berbeda dari domain publik, konfigurasikan serverActions.allowedOrigins agar permintaan lintas-host yang sah tidak dibatalkan diam-diam. Untuk operasi mahal, mengirim email, menulis ke basis data, memverifikasi kredensial, tambahkan rate limiting per pengguna atau IP, karena endpoint publik tanpa pembatasan adalah undangan terbuka bagi penyalahgunaan dan credential stuffing.

Saya juga menjaga aksi tetap ramping dengan mendorong autentikasi, otorisasi, dan logika basis data ke Data Access Layer khusus-server, lalu membuat fungsi use server mendelegasikan ke sana. Ini memusatkan pemeriksaan agar konsisten dan mudah diaudit, serta menjaga rahasia dan akses process.env di satu tempat. Dua kebiasaan lagi: kembalikan hanya yang dibutuhkan UI alih-alih baris mentah, dan jangan pernah menangkap data sensitif dalam closure aksi, karena variabel yang tertutup berpindah ke klien dan kembali, hanya terlindungi enkripsi yang tidak boleh Anda andalkan sendirian.

## Tetap ter-patch: RCE React2Shell, CVE-2025-66478

Pemeriksaan tingkat aplikasi tidak menyelamatkan Anda dari cacat tingkat framework, dan 2025 menghadirkan yang parah. Pada 3 Desember 2025, Next.js mengumumkan CVE-2025-66478, dampak hilir App Router dari kerentanan React hulu, CVE-2025-55182, dijuluki React2Shell. Ia diberi peringkat CVSS 10.0. Protokol React Server Components mendeserialisasi masukan tak tepercaya dengan cara yang, dalam kondisi tertentu, memungkinkan permintaan yang dirancang memicu jalur eksekusi server tak diinginkan, menghasilkan remote code execution, tanpa autentikasi apa pun.

Versi yang terdampak adalah Next.js 15.x, 16.x, dan rilis canary sejak 14.3.0-canary.77 dan seterusnya, saat menggunakan React Server Components dengan App Router. Next.js 13.x, 14.x stabil, aplikasi Pages Router, dan Edge Runtime tidak terdampak. Rilis perbaikan mencakup 15.0.5, 15.1.9, 15.2.6, 15.3.6, 15.4.8, 15.5.7, dan 16.0.7. Tidak ada solusi sementara; memperbarui wajib, dan Vercel menyarankan merotasi rahasia aplikasi setelah mem-patch dan me-redeploy.

Pelajarannya berpasangan dengan semua di atas. Auth dan validasi per-aksi Anda adalah kontrol yang Anda miliki, dan Anda harus melakukannya dengan benar, karena itulah pembeda antara aplikasi yang terkunci rapat dan API terbuka. Namun Anda juga berutang pada pengguna sebuah kebiasaan pembaruan yang membosankan dan disiplin, sehingga ketika CVSS 10.0 mendarat di hari Jumat, Anda sudah berada di lini yang ter-patch atau satu perintah dari sana. Keamanan adalah batas ditambah patch, bukan salah satu saja.

## Sources

- Dokumentasi Next.js, How to think about data security in Next.js
- Dokumentasi Next.js, How to implement authentication in Next.js
- Next.js Security Advisory, CVE-2025-66478 (React2Shell)
- OWASP, Insecure Direct Object Reference Prevention Cheat Sheet

## Source links

- https://nextjs.org/docs/app/guides/data-security
- https://nextjs.org/docs/app/guides/authentication
- https://nextjs.org/blog/CVE-2025-66478
- https://cheatsheetseries.owasp.org/cheatsheets/Insecure_Direct_Object_Reference_Prevention_Cheat_Sheet.html

## FAQ

### Apakah Next.js Server Actions aman secara bawaan?

Tidak. Setiap fungsi use server yang diekspor dikompilasi menjadi endpoint POST publik yang dapat dijangkau lewat permintaan langsung, bukan hanya melalui UI Anda. Next.js menambahkan ID aksi terenkripsi dan pemeriksaan CSRF Origin/Host, tetapi itu bukan otorisasi. Anda harus memverifikasi autentikasi dan otorisasi di dalam setiap aksi sendiri.

### Apakah tipe TypeScript atau validasi sisi klien melindungi Server Action?

Tidak. Tipe dan skema Zod sisi klien hanya berjalan di browser, yang sepenuhnya dikendalikan penyerang. Mereka bisa membaca ID aksi dan mengulang POST dengan payload apa pun. Semua validasi yang penting untuk keamanan harus berjalan di sisi server di dalam aksi, biasanya dengan Zod safeParse di batas masukan.

### Bagaimana mencegah IDOR pada Next.js Server Action?

Autentikasi saja tidak cukup, karena pengguna login mana pun bisa mengirim ID catatan milik orang lain. Setelah autentikasi, muat baris target dari basis data dan pastikan ia milik pemanggil (misalnya memeriksa post.authorId sama dengan ID pengguna sesi) sebelum melakukan mutasi. Jika tidak, lemparkan Forbidden.

### Apakah pemeriksaan auth tingkat halaman melindungi Server Actions di halaman itu?

Tidak. Redirect halaman atau pemeriksaan proxy hanya mengatur UI mana yang dirender. Server Action adalah titik masuk terpisah dan harus memverifikasi ulang pemanggil sendiri. Dokumentasi Next.js menyebut pemeriksaan autentikasi di dalam aksi sebagai kritis justru karena alasan ini.

### Apa itu CVE-2025-66478 dan versi Next.js mana yang terdampak?

CVE-2025-66478 (React2Shell) adalah cacat remote code execution CVSS 10.0 yang diumumkan pada 3 Desember 2025, berasal dari deserialisasi tidak aman pada protokol React Server Components. Ia terdampak pada Next.js 15.x, 16.x, dan build canary sejak 14.3.0-canary.77 yang memakai App Router. Tidak ada solusi sementara; perbarui ke rilis ter-patch seperti 15.5.7 atau 16.0.7 dan rotasi rahasia.

---

- HTML version: https://www.matthewswong.com/id/blog/nextjs-server-actions-security/
- English: https://www.matthewswong.com/en/blog/nextjs-server-actions-security/
- Site index for agents: https://www.matthewswong.com/llms.txt
- Sitemap: https://www.matthewswong.com/sitemap.xml
- API description (OpenAPI): https://www.matthewswong.com/openapi.json
