Menghosting data pengguna dengan aman di aplikasi web modern

David Dworken
David Dworken

Banyak aplikasi web perlu menampilkan konten yang dikontrol pengguna. Hal ini bisa 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 pada sebagian besar jenis aplikasi web.

Solusi klasik untuk mengisolasi konten yang tidak tepercaya

Solusi klasik untuk menayangkan konten yang dikontrol pengguna secara aman adalah dengan menggunakan apa yang dikenal sebagai domain sandbox. Gagasan 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 di exampleusercontent.com tidak dapat memengaruhi example.com. Pendekatan ini dapat digunakan untuk menyajikan semua jenis konten yang tidak tepercaya dengan aman, termasuk gambar, download, dan HTML. Meskipun mungkin tidak terlihat perlu menggunakan ini untuk gambar atau download, tindakan ini membantu menghindari risiko dari pengintaian konten, terutama di browser lama. Domain sandbox banyak digunakan di seluruh industri dan telah berfungsi dengan baik sejak lama. Namun, ada dua kekurangan 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 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 menyerang data lain di domain sandbox (misalnya, dengan membaca data asal yang sama).

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

Solusi modern untuk menyajikan konten pengguna

Seiring waktu, web telah berkembang, dan kini ada cara yang lebih mudah dan aman untuk menayangkan konten yang tidak tepercaya. Ada banyak pendekatan berbeda di sini, jadi kami akan menguraikan dua solusi yang kami gunakan 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 terisolasi. Ada dua langkah utama:

  • Selalu tetapkan header Content-Type ke jenis MIME terkenal yang didukung oleh semua browser dan tidak berisi konten aktif. Jika ragu, application/octet-stream adalah pilihan yang aman.
  • Selain itu, selalu tetapkan header respons untuk memastikan browser mengisolasi respons sepenuhnya.
Header Respons Tujuan

X-Content-Type-Options: nosniff

Mencegah pengintipan konten

Content-Disposition: attachment; filename="download"

Memicu download, bukan merender

Content-Security-Policy: sandbox

Mengisolasi konten seolah-olah disajikan di domain terpisah

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

Menonaktifkan eksekusi JavaScript (dan penyertaan subresource apa pun)

Cross-Origin-Resource-Policy: same-site

Mencegah halaman disertakan di seluruh situs

Kombinasi header ini memastikan bahwa respons hanya dapat dimuat sebagai subresource 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 memberikan tingkat keyakinan yang tinggi bahwa respons yang disajikan dengan cara ini tidak dapat menyebabkan kerentanan injeksi atau isolasi.

Defense in depth

Meskipun solusi yang diusulkan merupakan pertahanan yang cukup memadai terhadap XSS, ada sejumlah langkah penguatan 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 mencegah penyematan endpoint.
  • Menyandbox 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: Menyajikan 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 tidak semua browser web menerapkan isolasi proses untuk dokumen sandbox, penyempurnaan berkelanjutan pada model proses browser kemungkinan akan meningkatkan pemisahan konten sandbox dari aplikasi penyematan. Jika serangan SpectreJS dan kompromi perender berada di luar model ancaman Anda, maka penggunaan sandbox CSP kemungkinan merupakan solusi yang memadai. Di Google, kami telah mengembangkan solusi yang dapat mengisolasi sepenuhnya konten aktif yang tidak tepercaya dengan memodernisasi konsep domain sandbox. Ide intinya adalah:

  • 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 dan dengan demikian 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 membuat iframe atau dialog untuk $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 sandbox.

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

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.