Bagaimana Caputchin men-sandbox game
Sebuah game Caputchin adalah kode pihak-ketiga yang berjalan di peramban pengunjungmu, di halamanmu. Entah ia datang dari marketplace atau kamu hosting sendiri, Caputchin memperlakukannya sebagai tak dipercaya secara baku dan membungkusnya dalam beberapa lapis isolasi independen, jadi sebuah game yang buggy atau bermusuhan bisa merender, bermain, dan melaporkan hasil, tapi tak bisa menjangkau apa pun yang lain: bukan halamanmu, bukan data pengunjungmu, bukan jaringan.
Halaman ini menjelaskan setiap ukuran, mengapa masing-masing ada, dan bagaimana keseluruhannya berinteraksi dengan CSP yang kamu tambahkan ke situsmu sendiri.
Model ancaman dalam satu baris
Game menjalankan JavaScript sembarang (dan mungkin WebAssembly) yang dipasok pihak ketiga. Tujuan isolasinya karena itu: game bisa mengomputasi dan menggambar, dan ia bisa menyerahkan hasil kembali ke widget, tapi ia tak bisa membaca atau memengaruhi apa pun di luar frame-nya sendiri. Setiap lapis di bawah melayani satu tujuan itu, dan mereka adalah pertahanan berlapis, tak ada satu lapis pun yang dipercaya sempurna.
Lapis 1: iframe ber-sandbox origin-opaque
Setiap game berjalan di dalam sebuah <iframe> yang dibangun widget dengan atribut sandbox yang sengaja minimal. Token satu-satunya yang diberikan adalah allow-scripts, karena game adalah JavaScript dan harus berjalan. Semua yang lain ditahan, dan kelalaian terpenting adalah allow-same-origin.
Tanpa allow-same-origin peramban memberi frame sebuah origin null yang unik. Satu fakta itu adalah batas penyangga-beban:
- Game tak bisa membaca DOM halamanmu, cookie,
localStorage, atau sesi Caputchin, ia tersegel ke origin sekali-pakai yang asing bagimu. - Karena frame juga tak pernah bisa menavigasi jendela atasmu, membuka popup, mengirim formulir, atau memunculkan dialog native (semua kemampuan itu adalah token sandbox yang tak diberikan Caputchin), tak ada jalur dari game kembali keluar ke halamanmu.
Kombinasi allow-scripts tanpa allow-same-origin adalah seluruh intinya: peramban mengeksekusi kode game tapi memperlakukan frame sebagai origin asing yang tak bisa menyentuh apa pun milikmu. Caputchin tak pernah menambahkan allow-same-origin ke frame game. (Sebagai konsekuensi, setiap pesan yang diposting game ke widget tiba dari origin "null", yang diharapkan pemeriksaan kanal widget, origin non-null akan dengan sendirinya menandakan sandbox yang salah-konfigurasi.)
Lapis 2: dokumen frame dibangun inline, bukan diambil
Widget tak mengarahkan iframe ke halaman jarak-jauh. Ia membangun seluruh dokumen HTML frame inline (lewat srcdoc) dan menyerahkannya ke frame origin-null. Dokumen itu mungil: sebuah tag meta CSP ketat (lapis berikutnya), bootstrap runtime Caputchin kecil, dan satu tag <script> yang memuat bundel game.
Ini adalah mekanisme yang sama untuk kedua jalur pengiriman, hanya URL bundel yang berbeda:
| Sumber game | URL bundel di dokumen inline |
|---|---|
| Marketplace (diselesaikan-platform) | URL bundel ber-hash-integritas yang dipin yang Caputchin selesaikan saat mount. |
Swahosting (game-src-mu) | URL yang kamu pasok. |
Karena dokumen ditulis oleh widget ketimbang game, game tak pernah mengendalikan CSP, runtime, atau struktur frame, hanya apa yang bundel-nya sendiri lakukan setelah dimuat.
Lapis 3: Subresource Integrity untuk game marketplace
Saat Caputchin menyajikan game marketplace ia memin bundel ke versi tak-berubah dan mencatat hash kriptografi (SHA-384)-nya. Tag <script> yang memuat bundel membawa hash itu sebagai atribut integrity dengan crossorigin="anonymous", jadi peramban itu sendiri menolak mengeksekusi bundel jika satu byte berbeda dari yang dipin. CDN yang dikompromikan tak bisa menggantikan kode berbeda; muatan gagal tertutup.
Sebuah game swahosting tak punya hash yang ditegaskan-platform (kamu adalah akar kepercayaan untuk byte-mu sendiri), jadi atribut integrity sekadar dihilangkan untuk jalur itu. Lihat kontrak putar-ulang untuk bagaimana hasil sebuah game marketplace diturunkan-ulang secara independen di server, sebuah jaminan terpisah dari integritas.
Lapis 4: Content-Security-Policy inline yang ketat
Dokumen inline membawa Content-Security-Policy yang ketat. Meski frame sudah origin-null dan ber-sandbox, CSP lebih jauh membatasi apa yang boleh dilakukan kode yang dimuat, ia menolak semua secara baku dan memberi-ulang hanya minimum:
| Direktif | Nilai | Mengapa |
|---|---|---|
default-src | 'none' | Tolak semua yang tak diizinkan eksplisit di bawah. |
script-src | hash runtime inline Caputchin sendiri + origin bundel game + 'wasm-unsafe-eval' | Jalankan hanya bootstrap persis Caputchin (dipin oleh hash sha256-, bukan 'unsafe-inline') dan bundel game sendiri. 'wasm-unsafe-eval' membiarkan mesin WASM mengompilasi tanpa memberikan 'unsafe-eval' penuh. |
connect-src | 'none' | Direktif anti-eksfiltrasi. Game tak bisa fetch, XHR, membuka WebSocket, atau beacon ke mana pun. Tak ada egress jaringan sama sekali. |
img-src | data: (plus origin aset-skin mana pun, di bawah) | Sprite inline, atau dari host aset yang diizinkan. |
media-src | data: (plus origin aset-skin mana pun, di bawah) | Audio/video inline, atau dari host aset yang diizinkan. |
font-src | data: | Hanya font inline. |
style-src | 'unsafe-inline' | Game menyetel gaya inline; tanpa stylesheet eksternal. (Gaya tak bisa mengeksfiltrasi data cara skrip atau jaringan bisa.) |
Efek bersihnya: game berjalan, merender, dan melaporkan hasilnya lewat jembatan SDK, dan tak bisa menjangkau apa pun yang lain, khususnya bukan jaringan. CSP ini disetel Caputchin dan bukan sesuatu yang kamu konfigurasi; ia didaftarkan di sini agar kamu memahami persis betapa terkurungnya sebuah game.
Satu tempat di mana pengaturan pelanggan melebarkan CSP frame
Skin bisa mengarahkan bidang gambar atau audio ke URL absolut di CDN-mu sendiri (lihat skin). Agar aset itu memuat di dalam frame terkunci, Caputchin menambahkan hanya origin aset persis itu ke img-src / media-src frame, dan tak ke tempat lain. script-src dan connect-src tak pernah dilebarkan, jadi bahkan origin aset yang diizinkan tak bisa dipakai untuk memuat kode atau membuka kanal jaringan. Ini adalah satu-satunya cara sempit sebuah nilai terkonfigurasi memengaruhi kebijakan frame, dan ia masih hanya-aset.
Lapis 5: kanal hasil satu-arah
Game tak punya permukaan yang bisa dipanggil ke halamanmu. Satu-satunya jalan keluar adalah jembatan SDK: game memanggil satu metode yang postMessage-kan hasil opaque-nya (trace-nya) ke widget, yang hidup di origin-mu. Widget adalah yang berbicara ke API Caputchin; game tak pernah (ia tak bisa, connect-src adalah 'none'). Jadi jalur kepercayaan adalah game → widget → backend-mu, dan tiap lompatan hanya pernah meneruskan hasil ke depan, tak pernah memberi game jangkauan ke belakang.
CSP yang kamu setel di halamanmu sendiri
Lapis di atas melindungi kamu dan pengunjungmu dari game. Sebuah Content-Security-Policy di halamanmu sendiri adalah kontrol berbeda yang saling melengkapi: ia melindungi halamanmu dari segalanya, dan Caputchin dirancang untuk berjalan di bawah yang ketat. Kamu tak harus melonggarkan CSP-mu untuk menyematkan Caputchin; kamu harus mengizinkan beberapa origin yang dipakai widget secara sah.
Minimal, widget butuh:
| Direktif | Izinkan | Mengapa |
|---|---|---|
script-src | origin tempat kamu memuat skrip widget, plus 'unsafe-eval' | <script> yang mendefinisikan <caputchin-widget> / <caputchin-game>, CDN yang kamu pilih (jsDelivr, host-mu sendiri, atau caputchin.com). 'unsafe-eval' membiarkan tantangan instrumentasi berjalan; ia wajib selagi instrumentasi menyala, dan kamu bisa menghilangkannya dengan mematikan instrumentasi di halaman Keamanan key. |
connect-src | https://caputchin.com | Widget memanggil API Caputchin untuk menyiapkan dan memastikan sebuah verifikasi. Jika kamu mengarahkan widget ke host API berbeda, izinkan itu sebagai gantinya. |
frame-src | https://caputchin.com | Mengatur iframe game. Karena frame memakai dokumen srcdoc inline, peramban menerapkan frame-src-mu padanya, jadi izinkan origin Caputchin di sini. |
worker-src | blob: | Pemecah proof-of-work berjalan sepenuhnya di Web Worker yang dibuat dari URL blob:, tanpa cadangan thread-utama, jadi ini wajib. Jika kamu menghilangkan worker-src, peramban jatuh ke child-src lalu default-src, dan default-src 'self' sendiri tak mengizinkan blob:. |
Opsional tambahkan 'wasm-unsafe-eval' ke script-src: ia membiarkan pemecah proof-of-work berjalan sebagai WebAssembly cepat. Ia tak wajib, pemecah jatuh ke implementasi JavaScript murni yang lebih lambat (masih di dalam Worker) tanpanya.
Kamu tak perlu mengizinkan origin bundel game sendiri (jsDelivr, CDN game, host game-src-mu) di CSP halamanmu: bundel itu memuat di dalam frame ber-sandbox, di bawah CSP frame sendiri yang dijelaskan di atas, bukan di bawah kebijakan halamanmu. Halamanmu hanya mem-frame Caputchin; Caputchin mengurung apa yang berjalan di dalam.
Jika sebuah elemen Caputchin diam-diam gagal memuat di bawah CSP-mu, konsol peramban menyebut direktif yang diblokir; tambahkan origin atau keyword yang ia sebut ke direktif itu. Mulai ketat dan buka persis apa yang diminta konsol. Kamu tak pernah butuh 'unsafe-inline'. Kamu memang butuh blob: untuk worker (worker-src) dan, selagi instrumentasi menyala, 'unsafe-eval' di script-src; syarat 'unsafe-eval' lenyap jika kamu mematikan instrumentasi di halaman Keamanan key. 'wasm-unsafe-eval' opsional (ia mempercepat pemecah proof-of-work, yang kalau tidak berjalan lebih lambat dalam JavaScript di dalam Worker yang sama).
Mengapa begitu banyak lapis
Tiap lapis akan menjadi batas bermakna sendiri; bersama mereka berarti kegagalan di satu bukan pelanggaran. Origin null sendiri sudah menembok game dari datamu; CSP sendiri sudah mematikan egress jaringan; integritas sendiri sudah memin byte persisnya. Caputchin menjalankan semuanya karena kode pihak-ketiga tak-dipercaya adalah persis tempat pertahanan berlapis membuktikan kegunaannya.
Lihat juga
- Bagaimana game menahan bot: sisi server-otoritatif dari integritas game.
- Kontrak putar-ulang: bagaimana hasil sebuah game diturunkan-ulang secara independen di sisi-server.
- Bangun game swahosting: kendala bundel yang sandbox ini bebankan pada penulis.
- Muat widget dari CDN: memilih origin skrip yang harus diizinkan CSP halamanmu.