Menghosting data pengguna dengan aman di aplikasi web modern

David Dworken
David Dworken

Banyak aplikasi web perlu menampilkan konten yang dikontrol pengguna. Hal ini dapat sesederhana menayangkan gambar yang diupload pengguna (misalnya, foto profil), atau serumit merender HTML yang dikontrol pengguna (misalnya, tutorial pengembangan web). Hal ini selalu sulit dilakukan dengan aman, jadi kami telah berupaya menemukan solusi yang mudah, tetapi aman yang dapat diterapkan ke sebagian besar jenis aplikasi web.

Solusi klasik untuk mengisolasi konten yang tidak tepercaya

Solusi klasik untuk menayangkan konten yang dikontrol pengguna dengan aman adalah menggunakan apa yang disebut domain sandbox. Ide dasarnya adalah jika domain utama aplikasi Anda adalah example.com, Anda dapat menayangkan semua konten yang tidak tepercaya di exampleusercontent.com. Karena kedua domain ini bersifat lintas situs, konten berbahaya apa pun di exampleusercontent.com tidak dapat memengaruhi example.com.
Pendekatan ini dapat digunakan untuk menayangkan semua jenis konten tidak tepercaya dengan aman, termasuk gambar, download, dan HTML. Meskipun tampaknya tidak perlu menggunakan ini untuk gambar atau download, tindakan ini membantu menghindari risiko dari sniffing konten, terutama di browser lama.
Domain sandbox banyak digunakan di seluruh industri dan telah berfungsi dengan baik selama bertahun-tahun. Namun, ada dua kelemahan utama:

  • Aplikasi sering kali perlu membatasi akses konten ke satu pengguna, yang memerlukan penerapan autentikasi dan otorisasi. Karena domain sandbox sengaja tidak membagikan cookie dengan domain aplikasi utama, hal ini sangat sulit dilakukan dengan aman. Untuk mendukung autentikasi, situs harus mengandalkan URL kemampuan, atau harus menetapkan cookie autentikasi terpisah untuk domain sandbox. Metode kedua ini sangat bermasalah di web modern karena banyak browser yang membatasi cookie lintas situs secara default.
  • Meskipun konten pengguna diisolasi dari situs utama, konten tersebut tidak diisolasi dari konten pengguna lain. Hal ini menimbulkan risiko konten pengguna berbahaya yang menyerang data lain di domain sandbox (misalnya, melalui pembacaan data dengan origin yang sama).

Perlu juga diperhatikan bahwa domain sandbox membantu memitigasi risiko phishing karena resource disegmentasikan dengan jelas ke domain yang terisolasi.

Solusi modern untuk menayangkan konten pengguna

Seiring waktu, web telah berkembang, dan kini ada cara yang lebih mudah dan lebih aman untuk menayangkan konten yang tidak tepercaya. Ada banyak pendekatan yang berbeda di sini, jadi kami akan menguraikan dua solusi yang saat ini banyak digunakan di Google.

Pendekatan 1: Menayangkan konten pengguna tidak aktif

Jika situs hanya perlu menayangkan konten pengguna yang tidak aktif (yaitu konten yang bukan HTML atau JavaScript, misalnya gambar dan download), hal ini kini dapat dilakukan dengan aman tanpa domain sandbox yang terisolasi. Ada dua langkah utama:

  • Selalu tetapkan header Content-Type ke jenis MIME yang dikenal luas dan didukung oleh semua browser serta dijamin tidak berisi konten aktif (jika ragu, application/octet-stream adalah pilihan yang aman).
  • Selain itu, selalu tetapkan header respons di bawah untuk memastikan browser sepenuhnya mengisolasi respons.
Header Respons Tujuan

X-Content-Type-Options: nosniff

Mencegah sniffing konten

Content-Disposition: attachment; filename="download"

Memicu download, bukan rendering

Content-Security-Policy: sandbox

Menempatkan konten dalam sandbox seolah-olah konten tersebut ditayangkan di domain terpisah

Content-Security-Policy: default-src ‘none'

Menonaktifkan eksekusi JavaScript (dan penyertaan sub-resource apa pun)

Cross-Origin-Resource-Policy: same-site

Mencegah halaman disertakan secara lintas situs

Kombinasi header ini memastikan bahwa respons hanya dapat dimuat sebagai sub-resource oleh aplikasi Anda, atau didownload sebagai file oleh pengguna. Selain itu, header ini memberikan beberapa lapisan perlindungan terhadap bug browser melalui header sandbox CSP dan batasan default-src. Secara keseluruhan, penyiapan yang diuraikan di atas memberikan tingkat keyakinan yang tinggi bahwa respons yang ditayangkan dengan cara ini tidak dapat menyebabkan kerentanan injeksi atau isolasi.

Defense in depth

Meskipun solusi di atas secara umum cukup untuk melindungi dari XSS, ada sejumlah langkah hardening tambahan yang dapat Anda terapkan untuk memberikan lapisan keamanan tambahan:

  • Tetapkan header X-Content-Security-Policy: sandbox untuk kompatibilitas dengan IE11.
  • Tetapkan header Content-Security-Policy: frame-ancestors 'none' untuk memblokir endpoint agar tidak disematkan.
  • Mengisolasi konten pengguna di subdomain terisolasi dengan:
    • Menayangkan konten pengguna di subdomain terisolasi (misalnya, Google menggunakan domain seperti product.usercontent.google.com).
    • Tetapkan Cross-Origin-Opener-Policy: same-origin dan Cross-Origin-Embedder-Policy: require-corp untuk mengaktifkan isolasi lintas asal.

Pendekatan 2: Menayangkan konten pengguna aktif

Menayangkan konten aktif dengan aman (misalnya, gambar HTML atau SVG) juga dapat dilakukan tanpa kelemahan pendekatan domain sandbox klasik.
Opsi paling sederhana adalah memanfaatkan header Content-Security-Policy: sandbox untuk memberi tahu browser agar mengisolasi respons. Meskipun saat ini tidak semua browser web menerapkan isolasi proses untuk dokumen sandbox, peningkatan berkelanjutan pada model proses browser kemungkinan akan meningkatkan pemisahan konten dengan sandbox dari aplikasi penyematan. Jika serangan SpectreJS dan kompromi perender berada di luar model ancaman Anda, menggunakan sandbox CSP mungkin merupakan solusi yang memadai.
Di Google, kami telah mengembangkan solusi yang dapat sepenuhnya mengisolasi konten aktif yang tidak tepercaya dengan memodernisasi konsep domain sandbox. Ide utamanya adalah untuk:

  • Buat domain sandbox baru yang ditambahkan ke daftar akhiran publik. Misalnya, dengan menambahkan exampleusercontent.com ke PSL, Anda dapat memastikan bahwa foo.exampleusercontent.com dan bar.exampleusercontent.com bersifat lintas situs sehingga sepenuhnya terisolasi satu sama lain.
  • Semua URL yang cocok dengan *.exampleusercontent.com/shim akan dirutekan ke file shim statis. File shim ini berisi cuplikan HTML dan JavaScript singkat yang memproses pengendali peristiwa message dan merender konten apa pun yang diterimanya.
  • Untuk menggunakannya, produk akan membuat iframe atau pop-up ke $RANDOM_VALUE.exampleusercontent.com/shim dan menggunakan postMessage untuk mengirim konten yang tidak tepercaya ke shim untuk dirender.
  • Konten yang dirender diubah menjadi Blob dan dirender di dalam iframe dengan sandbox.

Dibandingkan dengan pendekatan domain sandbox klasik, pendekatan ini memastikan bahwa semua konten sepenuhnya terisolasi di situs unik. Selain itu, dengan membuat aplikasi utama menangani pengambilan data yang akan dirender, Anda tidak perlu lagi menggunakan URL kemampuan.

Kesimpulan

Bersama-sama, kedua solusi ini memungkinkan migrasi dari domain sandbox klasik seperti googleusercontent.com ke solusi yang lebih aman dan kompatibel dengan pemblokiran cookie pihak ketiga. Di Google, kami telah memigrasikan banyak produk untuk menggunakan solusi ini dan merencanakan lebih banyak migrasi untuk tahun depan.