Memuat...
👋 Selamat Pagi!

Deserialization Attack di React Server Components dan Cara Mitigasinya

RSC membawa risiko keamanan baru lewat Flight protocol. Panduan teknis memahami deserialization sink dan cara mitigasinya sebelum deploy ke production.

Deserialization Attack di React Server Components dan Cara Mitigasinya

React Server Components (RSC) mengubah cara kita membangun aplikasi React modern dengan performa yang jauh lebih baik.

Tapi ada satu hal yang sering diabaikan developer: RSC membawa risiko keamanan baru yang tidak ada di Client Components biasa.

Flight protocol yang menjadi tulang punggung RSC ternyata punya celah deserialization yang bisa dieksploitasi attacker untuk menjalankan kode berbahaya di server kamu.

Artikel ini akan membahas secara mendalam bagaimana deserialization attack bekerja di RSC, skenario serangan nyata, dan checklist mitigasi yang wajib kamu terapkan sebelum deploy ke production.

Sekilas Ulang: Bagaimana React Flight Protocol Bekerja di RSC

Sebelum masuk ke pembahasan security, kita perlu paham dulu bagaimana Flight protocol bekerja.

Flight protocol adalah mekanisme serialisasi data yang digunakan React untuk mengirim Server Components dari server ke client.

Berbeda dengan JSON biasa, Flight protocol bisa serialize fungsi, Promise, bahkan React elements secara native.

Ketika kamu render Server Component, React mengkonversi component tree menjadi stream data khusus yang dikirim ke browser.

Browser kemudian deserialize stream tersebut dan merender UI yang sesuai.

Proses ini terjadi secara otomatis dan transparan, makanya banyak developer tidak menyadari ada serialization/deserialization yang terjadi di balik layar.

Flight protocol menggunakan format binary yang efisien, jauh lebih cepat dibanding JSON.parse() biasa.

Tapi kecepatan ini datang dengan tradeoff: lebih banyak fitur berarti lebih banyak attack surface.

Apa Itu Deserialization Sink dan Kenapa Berbahaya di RSC

Deserialization sink adalah titik dalam aplikasi dimana data eksternal di-deserialize menjadi object atau executable code.

Di aplikasi tradisional, deserialization biasanya terjadi saat parsing JSON dari API atau cookie.

Di RSC, deserialization terjadi setiap kali Flight protocol mengkonversi stream data menjadi component tree.

Masalahnya, Flight protocol tidak hanya deserialize data sederhana seperti string atau number.

Protocol ini bisa deserialize object kompleks, fungsi, bahkan reference ke module JavaScript di server.

Bayangkan kamu punya Server Component yang menerima props dari user input tanpa validasi.

Attacker bisa craft payload khusus yang ketika di-deserialize, menjalankan kode arbitrary di server kamu.

Ini bukan serangan XSS biasa yang cuma berjalan di browser user.

Ini adalah Remote Code Execution (RCE) yang berjalan di server dengan akses penuh ke database, environment variables, dan resource lainnya.

Severity-nya jauh lebih tinggi dibanding vulnerability client-side.

Skenario Serangan Nyata: Bagaimana Attacker Mengeksploitasi Flight Protocol

Mari kita lihat skenario konkret bagaimana serangan ini bekerja.

Misalkan kamu punya Server Component yang render user profile berdasarkan query parameter:

// app/profile/page.js - Server Component
export default async function ProfilePage({ searchParams }) {
  const userPrefs = searchParams.prefs; // User input tidak divalidasi
  
  return <UserProfile preferences={userPrefs} />;
}

Code di atas terlihat innocent, tapi sangat vulnerable.

Attacker bisa craft URL dengan payload khusus di query parameter prefs.

Payload ini mengandung serialized object yang ketika di-deserialize oleh Flight protocol, mengeksekusi kode berbahaya.

Contoh payload yang mungkin:

// Payload yang di-encode di URL
{
  "__proto__": {
    "isAdmin": true
  },
  "dangerousFunction": "require('child_process').exec('rm -rf /')"
}

Ketika Flight protocol deserialize payload ini, prototype pollution bisa terjadi.

Attacker bisa override property object, bahkan inject fungsi yang akan dieksekusi saat component render.

Skenario lain yang lebih subtle: Server Action yang menerima form data tanpa validasi.

// app/actions.js
'use server'

export async function updateUserSettings(formData) {
  const settings = JSON.parse(formData.get('settings')); // Vulnerable!
  await db.users.update({ settings });
}

Meskipun ini menggunakan JSON.parse biasa, bukan Flight protocol, konsepnya sama.

Data dari client di-deserialize langsung tanpa validasi, membuka celah injection.

Yang lebih berbahaya, attacker bisa chain multiple vulnerabilities.

Misalnya combine prototype pollution dengan Server Action untuk escalate privilege atau bypass authentication.

Checklist Mitigasi: Validasi Input, Sanitasi Output, dan Trusted Types

Sekarang kita masuk ke bagian penting: bagaimana melindungi aplikasi RSC dari deserialization attack.

1. Validasi Input di Setiap Entry Point

Rule pertama dan terpenting: jangan pernah trust input dari client.

Setiap data yang masuk ke Server Component atau Server Action harus divalidasi dengan schema yang ketat.

Gunakan library validation seperti Zod untuk enforce type safety:

// app/actions.js
'use server'
import { z } from 'zod';

const settingsSchema = z.object({
  theme: z.enum(['light', 'dark']),
  notifications: z.boolean(),
  language: z.string().max(5)
});

export async function updateUserSettings(formData) {
  const rawSettings = formData.get('settings');
  
  // Validasi dengan Zod sebelum deserialize
  const result = settingsSchema.safeParse(JSON.parse(rawSettings));
  
  if (!result.success) {
    throw new Error('Invalid settings format');
  }
  
  await db.users.update({ settings: result.data });
}

Dengan pendekatan ini, hanya data yang match schema yang akan di-process.

Payload berbahaya otomatis ditolak sebelum sempat di-deserialize.

2. Sanitasi Output yang Benar

Input validation saja tidak cukup, kamu juga perlu sanitize output sebelum render.

Terutama untuk data yang berasal dari database atau external API yang mungkin sudah compromised.

React secara default escape string untuk mencegah XSS, tapi RSC punya attack vector tambahan.

Gunakan DOMPurify atau library sanitization lain untuk clean HTML yang akan di-render:

import DOMPurify from 'isomorphic-dompurify';

export default async function BlogPost({ id }) {
  const post = await db.posts.findById(id);
  
  // Sanitize HTML content
  const cleanContent = DOMPurify.sanitize(post.content, {
    ALLOWED_TAGS: ['p', 'br', 'strong', 'em', 'a'],
    ALLOWED_ATTR: ['href']
  });
  
  return <article dangerouslySetInnerHTML={{ __html: cleanContent }} />;
}

Whitelist approach seperti di atas jauh lebih aman dibanding blacklist.

3. Implementasi Trusted Types

Trusted Types adalah browser API yang membantu mencegah DOM-based XSS.

Meskipun ini fitur browser, kamu bisa leverage untuk protect deserialization di RSC.

Aktifkan Trusted Types dengan Content Security Policy header:

// next.config.js
module.exports = {
  async headers() {
    return [
      {
        source: '/:path*',
        headers: [
          {
            key: 'Content-Security-Policy',
            value: "require-trusted-types-for 'script'; trusted-types default"
          }
        ]
      }
    ];
  }
};

Dengan Trusted Types aktif, browser akan block assignment ke innerHTML atau eval yang tidak melalui trusted policy.

Ini mencegah attacker inject script meskipun berhasil bypass validation di server.

4. Batasi Serializable Data di Server Components

Jangan serialize object kompleks atau fungsi di Server Components jika tidak perlu.

Stick dengan primitive types dan plain object yang aman.

// ❌ BAHAYA - Serialize fungsi
export default function DangerousComponent() {
  return <ClientComponent callback={() => console.log('dangerous')} />;
}

// ✅ AMAN - Gunakan Server Action
'use server'
async function safeAction() {
  console.log('safe');
}

export default function SafeComponent() {
  return <ClientComponent action={safeAction} />;
}

Server Actions di-handle dengan lebih aman oleh React karena hanya function reference yang di-serialize, bukan implementation-nya.

5. Audit Dependencies Secara Berkala

Vulnerability sering datang dari third-party library yang kamu gunakan.

Pastikan semua dependencies up-to-date dan tidak punya known vulnerabilities:

npm audit fix

Gunakan tools seperti Snyk atau GitHub Dependabot untuk auto-detect security issues.

Set up automated pull requests untuk dependency updates agar tidak ketinggalan patch security.

Tools dan Library untuk Audit Keamanan RSC di Project Kamu

Berikut tools yang wajib ada di development workflow untuk detect vulnerability di RSC:

1. ESLint dengan Security Rules

Install plugin ESLint khusus untuk detect security anti-patterns:

npm install --save-dev eslint-plugin-security

Tambahkan di .eslintrc.js:

module.exports = {
  plugins: ['security'],
  extends: ['plugin:security/recommended'],
  rules: {
    'security/detect-object-injection': 'error',
    'security/detect-eval-with-expression': 'error'
  }
};

ESLint akan warning kamu saat ada code pattern yang berbahaya.

2. React Server Components Linter

Ada linter khusus untuk detect anti-pattern di RSC:

npm install --save-dev eslint-plugin-react-server-components

Plugin ini detect issues spesifik RSC seperti:

  • Serializing non-serializable objects
  • Using client-only APIs di Server Components
  • Improper data passing between server dan client

3. OWASP ZAP untuk Penetration Testing

OWASP ZAP adalah tool open-source untuk automated security testing.

Integrate ZAP di CI/CD pipeline untuk run security scan setiap kali deploy:

# .github/workflows/security-scan.yml
name: Security Scan
on: [push]
jobs:
  zap-scan:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - name: Run OWASP ZAP
        uses: zaproxy/[email protected]
        with:
          target: 'http://localhost:3000'

ZAP akan crawl aplikasi dan detect common vulnerabilities termasuk injection attacks.

4. Semgrep untuk Static Analysis

Semgrep adalah tool static analysis yang powerful untuk detect security issues di code.

Buat rules khusus untuk detect deserialization sink di RSC:

# semgrep-rules.yml
rules:
  - id: rsc-unsafe-deserialization
    pattern: JSON.parse($INPUT)
    message: Unsafe deserialization detected
    severity: ERROR
    languages: [javascript, typescript]

Jalankan Semgrep di pre-commit hook:

npx semgrep --config semgrep-rules.yml .

5. React DevTools Profiler

React DevTools punya Profiler mode yang bisa track component render dan detect suspicious behavior.

Gunakan untuk monitoring production dan detect anomali yang mungkin indikasi exploitation attempt.

Enable profiling di production dengan careful configuration:

// next.config.js
module.exports = {
  reactStrictMode: true,
  productionBrowserSourceMaps: true, // Untuk debugging
};

Jangan lupa disable production source maps setelah investigation selesai untuk prevent reverse engineering.

Butuh jasa pembuatan website profesional dengan standar keamanan tinggi? KerjaKode menyediakan layanan pembuatan website berkualitas tinggi dengan best practices security yang terintegrasi dari awal development. Kunjungi jasa pembuatan website KerjaKode untuk konsultasi gratis dan wujudkan website yang aman dan performa tinggi.

Best Practices Security untuk RSC di Production

Selain mitigasi teknis di atas, ada beberapa best practices operational yang wajib diterapkan:

Principle of Least Privilege

Server Components harus berjalan dengan minimal permission yang dibutuhkan.

Jangan run application server sebagai root user.

Batasi akses database hanya ke table yang benar-benar diperlukan.

Gunakan separate credentials untuk read-only operations dan write operations.

Defense in Depth

Jangan rely pada satu layer protection saja.

Combine multiple security measures: input validation, output sanitization, CSP, rate limiting, WAF, dll.

Jika satu layer gagal, layer lain masih bisa prevent exploitation.

Security Headers

Set proper security headers di Next.js config:

// next.config.js
module.exports = {
  async headers() {
    return [
      {
        source: '/:path*',
        headers: [
          { key: 'X-Frame-Options', value: 'DENY' },
          { key: 'X-Content-Type-Options', value: 'nosniff' },
          { key: 'Referrer-Policy', value: 'strict-origin-when-cross-origin' },
          { key: 'Permissions-Policy', value: 'camera=(), microphone=(), geolocation=()' }
        ]
      }
    ];
  }
};

Headers ini mencegah berbagai attack vector di browser level.

Regular Security Audits

Schedule security audit minimal setiap quarter.

Hire external security researcher untuk penetration testing.

Join bug bounty program untuk crowdsource vulnerability discovery.

Buat incident response plan untuk handle breach jika terjadi.

Logging dan Monitoring

Implement comprehensive logging untuk detect suspicious activity.

Log setiap deserialization attempt dengan detail payload dan source IP.

Set up alert untuk pattern yang mencurigakan seperti:

  • Multiple failed validation attempts dari IP yang sama
  • Payload dengan size tidak normal
  • Request pattern yang berbeda dari traffic biasa
// middleware.js
export function middleware(request) {
  const payload = request.nextUrl.searchParams.toString();
  
  // Log suspicious patterns
  if (payload.includes('__proto__') || payload.length > 10000) {
    console.warn('Suspicious payload detected:', {
      ip: request.ip,
      payload: payload.substring(0, 100),
      timestamp: new Date().toISOString()
    });
  }
  
  return NextResponse.next();
}

Integrate dengan SIEM (Security Information and Event Management) untuk centralized monitoring.

Kesalahan Umum yang Harus Dihindari

Dari pengalaman menangani security incident di berbagai project RSC, ini beberapa mistake yang paling sering terjadi:

1. Menganggap Server Components Otomatis Aman

Banyak developer assume bahwa karena code berjalan di server, tidak ada security risk.

Padahal Server Components tetap receive input dari client yang bisa malicious.

Jangan skip validation cuma karena kode ada di server.

2. Over-trusting Serialized Data

Hanya karena data di-serialize dengan Flight protocol bukan berarti data tersebut safe.

Attacker bisa craft payload yang valid secara format tapi malicious secara konten.

Selalu validate content, bukan hanya format.

3. Menggunakan eval atau Function Constructor

Jangan pernah gunakan eval(), Function(), atau new Function() dengan input dari user.

Ini direct path ke RCE.

// ❌ SANGAT BERBAHAYA
const userCode = searchParams.get('code');
eval(userCode); // RCE vulnerability!

// ✅ Gunakan safe alternatives
const allowedOperations = {
  add: (a, b) => a + b,
  subtract: (a, b) => a - b
};
const operation = allowedOperations[searchParams.get('op')];

4. Expose Sensitive Data di Props

Jangan pass sensitive data seperti API keys atau credentials sebagai props ke Client Components.

Data di props bisa di-inspect di browser DevTools.

// ❌ BAHAYA
<ClientComponent apiKey={process.env.SECRET_KEY} />

// ✅ AMAN - Gunakan Server Action
'use server'
async function fetchDataWithKey() {
  return fetch(API_URL, {
    headers: { 'Authorization': `Bearer ${process.env.SECRET_KEY}` }
  });
}

5. Skip Security di Development Environment

Developer sering disable security measures di local development karena "ribet".

Ini dangerous karena security issues tidak terdetect sampai production.

Enforce same security rules di semua environment, termasuk local development.

Gunakan .env.local untuk development credentials, tapi tetap dengan validation yang sama.

Checklist Sebelum Deploy ke Production

Sebelum deploy aplikasi RSC ke production, pastikan semua items di checklist ini sudah completed:

Input Validation:

  • Semua Server Component props divalidasi dengan schema
  • Server Actions implement input validation
  • Query parameters dan form data di-sanitize
  • File uploads dibatasi type dan size

Output Safety:

  • HTML content di-sanitize dengan DOMPurify
  • User-generated content di-escape dengan benar
  • Trusted Types diaktifkan di CSP header

Dependencies:

  • Semua packages up-to-date
  • Tidak ada known vulnerabilities di npm audit
  • Dependencies minimal dan necessary only

Monitoring:

  • Logging diaktifkan untuk deserialization events
  • Alert setup untuk suspicious patterns
  • Error tracking terintegrasi (Sentry, etc.)

Security Headers:

  • CSP header configured dengan strict policy
  • X-Frame-Options, X-Content-Type-Options set
  • HTTPS enforced di production

Code Review:

  • Security-focused code review dilakukan
  • Automated security scan passed
  • Penetration testing completed

Documentation:

  • Security guidelines terdokumentasi untuk team
  • Incident response plan tersedia
  • Contact info security team tercantum

Jika ada satu item pun yang belum checked, jangan deploy dulu.

Security issue di production bisa cost reputasi dan finansial yang sangat besar.

Penutup

Deserialization attack di React Server Components adalah threat serius yang tidak boleh diabaikan.

Flight protocol membawa convenience dan performa, tapi juga membuka attack surface baru.

Dengan memahami bagaimana serangan bekerja dan menerapkan mitigasi yang proper, kamu bisa build aplikasi RSC yang aman.

Key takeaways dari artikel ini:

  • Validasi setiap input dari client tanpa exception
  • Sanitize output sebelum render
  • Gunakan tools automation untuk detect vulnerability early
  • Implement defense in depth strategy
  • Regular audit dan monitoring adalah must

Security bukan one-time effort, tapi continuous process yang harus jadi bagian dari development culture.

Stay vigilant dan keep learning tentang threat landscape yang terus berkembang.

Happy coding, dan stay secure!

Ajie Kusumadhany
Written by

Ajie Kusumadhany

Founder & Lead Developer KerjaKode. Berpengalaman dalam pengembangan web modern dengan Laravel, React.js, Vue.js, dan teknologi terkini. Passionate tentang coding, teknologi, dan berbagi pengetahuan melalui artikel.

Promo Spesial Hari Ini!

10% DISKON

Promo berakhir dalam:

00 Jam
:
00 Menit
:
00 Detik
Klaim Promo Sekarang!

*Promo berlaku untuk order hari ini

0
User Online
Halo! 👋
Kerjakode Support Online
×

👋 Hai! Pilih layanan yang kamu butuhkan:

Chat WhatsApp Sekarang