Pilih bahasa

Menguasai Seni Keamanan Progressive Web App

Progressive Web Apps (PWAs) telah menjadi standar de‑facto untuk memberikan pengalaman mirip aplikasi di web terbuka. Kekuatan inti mereka—kemampuan offline, notifikasi push, dan kemampuan di‑instal—juga memperkenalkan permukaan serangan baru yang jarang ditemui situs web tradisional. Artikel ini menyelami siklus hidup keamanan PWA, menggabungkan penguatan pada tingkat jaringan, perlindungan runtime, dan praktik operasional terbaik. Pada akhirnya, Anda akan memiliki daftar periksa yang dapat diterapkan pada proyek apa pun, baik itu pembaca berita sederhana atau platform e‑commerce yang kompleks.

TL;DR: Amankan PWA Anda dengan HTTPS, terapkan CSP ketat, sandbank service worker, validasi semua masukan, dan adopsi rutinitas pemantauan berkelanjutan.


1. Lapisan Transport – Garis Pertahanan Pertama

1.1 Terapkan HTTPS di Seluruh Tempat

Semua browser modern memaksa HTTPS untuk pendaftaran service worker. Namun, beberapa aset (misalnya analitik pihak ketiga) masih dapat dimuat lewat HTTP, menimbulkan peringatan mixed‑content dan membuka celah serangan man‑in‑the‑middle (MITM).

Langkah‑langkah kunci:

  1. Dapatkan sertifikat TLS tepercaya (Let’s Encrypt, Cloudflare, dll.).
  2. Alihkan semua permintaan http:// ke https:// melalui konfigurasi server.
  3. Aktifkan HSTS (HTTP Strict Transport Security) untuk memaksa browser menggunakan HTTPS selama periode yang ditentukan.
# Contoh potongan NGINX
server {
    listen 80;
    server_name example.com www.example.com;
    return 301 https://$host$request_uri;
}
server {
    listen 443 ssl http2;
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
    # Pengaturan TLS ...
}

Catatan: HSTS menghilangkan serangan penurunan, tetapi memerlukan perencanaan matang karena setelah diatur, browser akan menolak koneksi HTTP selama periode yang ditetapkan.

1.2 Certificate Pinning (Opsional)

Untuk PWA yang sangat sensitif—perbankan, catatan kesehatan—pertimbangkan certificate pinning melalui Public Key Pinning Extension for HTTP (HPKP). Meskipun HPKP sedang dihentikan karena risiko penyebarannya, Anda dapat memperoleh keamanan serupa dengan header Expect‑CT yang memaksa Certificate Transparency.

Expect-CT: max-age=86400, enforce, report-uri="https://example.com/report"

2. Penguatan Service Worker

Service worker merupakan inti kemampuan offline PWA. Mereka berjalan di thread latar dengan privilese tinggi, menjadikannya target utama eksploitasi.

2.1 Pembatasan Scope

Tentukan scope sekecil mungkin saat mendaftarkan service worker. Ini mencegah worker menangkap permintaan di luar area yang dimaksud.

navigator.serviceWorker.register('/sw.js', { scope: '/app/' })
  .then(reg => console.log('SW terdaftar dengan scope:', reg.scope));

2.2 Verifikasi Integritas dengan Subresource Integrity (SRI)

Jika Anda memuat skrip service worker dari CDN, lindungi dengan SRI agar kode yang diambil cocok dengan hash yang diharapkan.

<script src="https://cdn.example.com/sw.js"
        integrity="sha384-abc123..."
        crossorigin="anonymous"></script>

2.3 Content Security Policy untuk Service Worker

CSP yang ketat dapat mencegah worker memuat skrip berbahaya atau terhubung ke origin yang tidak diinginkan.

Content-Security-Policy: script-src 'self' https://trusted.cdn.com; 
                         connect-src 'self' https://api.example.com;

Tip: Gunakan direktif worker-src (didukung di browser terbaru) untuk secara eksplisit mengizinkan origin skrip worker.

2.4 Manajemen State dan Validasi Cache

Jangan pernah mempercayai entri cache secara membabi buta. Selalu validasi kesegaran respons yang di‑cache, terutama untuk token autentikasi atau data pribadi.

self.addEventListener('fetch', event => {
  const url = new URL(event.request.url);
  if (url.pathname.startsWith('/api/')) {
    // Lewati cache untuk data dinamis
    event.respondWith(fetch(event.request));
    return;
  }
  // Strategi default cache‑first untuk aset statis
  event.respondWith(
    caches.match(event.request).then(cached => cached || fetch(event.request))
  );
});

3. Perlindungan Runtime – CSP, Permissions, dan Sandbox

3.1 CSP Lengkap

CSP yang dirancang dengan baik mengurangi risiko Cross‑Site Scripting (XSS) dan Data Injection. Berikut contoh kebijakan yang disesuaikan untuk PWA tipikal:

Content-Security-Policy:
  default-src 'self';
  script-src 'self' 'sha256-XYZ' https://analytics.example.com;
  style-src 'self' 'unsafe-inline';
  img-src 'self' data:;
  font-src 'self' https://fonts.gstatic.com;
  connect-src 'self' https://api.example.com wss://socket.example.com;
  frame-ancestors 'none';
  base-uri 'self';
  form-action 'self';
  • script-src menyertakan hash untuk skrip inline agar tidak perlu unsafe-inline.
  • frame-ancestors 'none' menonaktifkan clickjacking.
  • connect-src mengizinkan API dan endpoint WebSocket yang sah.

3.2 Permissions Policy (Feature‑Policy Sebelumnya)

Batasi fitur browser yang kuat yang mungkin secara tidak sengaja diwarisi oleh PWA.

Permissions-Policy: geolocation=(), microphone=(), camera=(), payment=()

3.3 Atribut Sandbox untuk Konten Tersemat

Jika PWA Anda menyematkan iframe pihak ketiga, sandbank mereka untuk mencegah eksekusi skrip dan navigasi.

<iframe src="https://maps.example.com"
        sandbox="allow-scripts allow-same-origin"
        loading="lazy"></iframe>

4. Autentikasi & Otorisasi

4.1 Autentikasi Berbasis Token dengan JWT

Gunakan JSON Web Tokens (JWT) untuk autentikasi tanpa status, tetapi jangan pernah menyimpannya di localStorage—gunakan cookie Secure, HttpOnly untuk mengurangi pencurian lewat XSS.

Set-Cookie: token=eyJhbGciOi...; HttpOnly; Secure; SameSite=Strict; Path=/; Max-Age=3600

4.2 Rotasi Refresh Token

Implementasikan rotasi refresh token untuk membatasi dampak token yang dikompromikan.

  1. Klien mengirim refresh token.
  2. Server memvalidasi dan mengeluarkan token akses baru serta refresh token baru.
  3. Refresh token lama dinonaktifkan di basis data.

4.3 Mitigasi CSRF

Meskipun menggunakan cookie same‑site, gunakan token anti‑CSRF untuk permintaan POST yang mengubah status.

<input type="hidden" name="csrf_token" value="{{ .CSRFToken }}">

Di server, verifikasi bahwa token cocok dengan sesi.


5. Penyimpanan Data yang Aman

PWA dapat menyimpan data melalui IndexedDB, Cache API, dan Web Storage. Masing‑masing mempunyai pertimbangan keamanannya.

PenyimpananKesesuaianTips Keamanan
Cache APIAset statis, fallback offlineCache hanya sumber yang tidak berubah. Gunakan nama cache versi untuk membersihkan data usang.
IndexedDBData terstruktur, preferensi penggunaEnkripsi field sensitif di sisi klien dengan Web Crypto API.
LocalStorage / SessionStorageData kecil yang tidak sensitifHindari menyimpan rahasia. Data dapat diakses oleh skrip apapun pada halaman.

5.1 Contoh: Enkripsi Data di IndexedDB

async function encryptAndStore(key, value) {
  const cryptoKey = await crypto.subtle.generateKey(
    { name: "AES-GCM", length: 256 },
    true,
    ["encrypt", "decrypt"]
  );
  const iv = crypto.getRandomValues(new Uint8Array(12));
  const encoded = new TextEncoder().encode(value);
  const ciphertext = await crypto.subtle.encrypt(
    { name: "AES-GCM", iv },
    cryptoKey,
    encoded
  );
  const db = await openDB('secure-store', 1, {
    upgrade(db) { db.createObjectStore('secrets'); }
  });
  await db.put('secrets', { iv, ciphertext }, key);
}

6. Pemantauan, Audit, dan Respons Insiden

Keamanan bukan konfigurasi sekali saja; ia merupakan siklus berkelanjutan.

6.1 Pemindaian Otomatis

  • Gunakan OWASP ZAP atau Burp Suite untuk memindai XSS, CSRF, dan header yang tidak aman.
  • Integrasikan audit Lighthouse ke dalam pipeline CI/CD untuk menegakkan kepatuhan PWA.

6.2 Logging pada Runtime

Tangkap error service‑worker dan kirim ke endpoint aman untuk analisis.

self.addEventListener('error', event => {
  fetch('https://logs.example.com/collect', {
    method: 'POST',
    body: JSON.stringify({ message: event.message, stack: event.error.stack })
  });
});

6.3 Playbook Insiden

  1. Deteksi: Peringatan dari trafik abnormal atau laporan pelanggaran CSP.
  2. Karantina: Cabut JWT yang terkompromi, putar kembali API key.
  3. Eradikasi: Perbaiki kode yang rentan, perbarui cache service‑worker.
  4. Pemulihan: Deploy versi baru, pantau agar tidak kembali.
  5. Pasca‑mortem: Dokumentasikan akar penyebab, perbarui daftar periksa keamanan.

7. Gambaran Visual – Lapisan Keamanan dalam PWA

  flowchart TB
    subgraph "Lapisan Transport"
        H["\"HTTPS\""]
        S["\"HSTS\""]
    end
    subgraph "Service Worker"
        SW["\"Pembatasan Scope\""]
        CS["\"Validasi Cache\""]
    end
    subgraph "Runtime"
        CSP["\"Content Security Policy\""]
        PP["\"Permissions Policy\""]
        SAN["\"Sandboxed iFrames\""]
    end
    subgraph "Auth & Data"
        JWT["\"Secure Cookies\""]
        REF["\"Rotasi Refresh\""]
        ENC["\"Enkripsi IndexedDB\""]
    end
    subgraph "Monitoring"
        SCAN["\"OWASP ZAP\""]
        LOG["\"Runtime Logging\""]
    end

    H --> SW --> CSP --> JWT --> SCAN
    S --> SW
    CS --> PP
    PP --> ENC
    LOG --> SCAN

Diagram di atas menggambarkan bagaimana setiap kontrol keamanan membangun di atas yang sebelumnya, membentuk arsitektur defense‑in‑depth.


8. Daftar Periksa – Referensi Cepat untuk PWA yang Aman

  • Layani semua konten lewat HTTPS dengan HSTS diaktifkan.
  • Daftarkan service worker dengan scope sekecil mungkin.
  • Terapkan Subresource Integrity untuk skrip yang dimuat dari CDN.
  • Pakai CSP ketat, termasuk worker-src dan hash skrip.
  • Gunakan Permissions‑Policy untuk menonaktifkan fitur browser yang tidak dipakai.
  • Simpan token autentikasi dalam cookie Secure, HttpOnly; jangan di localStorage.
  • Rotasi refresh token dan validasi token CSRF pada permintaan yang mengubah status.
  • Enkripsi data sensitif di IndexedDB.
  • Jalankan pemindaian OWASP ZAP otomatis pada setiap PR.
  • Siapkan logging real‑time untuk error service‑worker.
  • Pertahankan playbook respons insiden.

9. Pertanyaan yang Sering Diajukan

T1: Apakah PWA memerlukan Service Worker untuk keamanan?
Tidak. Langkah keamanan seperti HTTPS, CSP, dan cookie aman berfungsi secara independen. Namun, Service Worker adalah tempat sebagian besar serangan runtime muncul, sehingga memerlukan penguatan ekstra.

T2: Bisakah saya memakai unsafe-inline di CSP untuk styling?
Sebaiknya hindari. Sebagai gantinya, gunakan hash atau nonce pada style inline, atau pindahkan ke file CSS eksternal.

T3: Seberapa sering saya harus mengganti sertifikat TLS?
Let’s Encrypt mengeluarkan sertifikat 90‑hari; otomatisasikan perpanjangannya. Untuk sertifikat self‑signed atau komersial, targetkan masa berlaku maksimal 1 tahun.


10. Kesimpulan

Progressive Web Apps mengaburkan batas antara pengalaman native dan web, memberi kemampuan kuat sekaligus memperluas permukaan serangan. Dengan memadukan keamanan transport, memperketat scope service‑worker, menegakkan Content Security Policy yang disiplin, serta menerapkan praktik autentikasi yang kuat, Anda dapat melindungi PWA tanpa mengorbankan performa.

Ingat: keamanan adalah perjalanan, bukan tujuan akhir. Tetap perbarui dependensi, audit kode secara rutin, dan ikuti perkembangan ancaman terbaru. Dengan menerapkan praktik yang dijabarkan di sini, PWA Anda akan tetap kuat melawan serangan web paling umum.


Lihat Juga

ke atas
© Scoutize Pty Ltd 2025. All Rights Reserved.