Caputchin
Caputchin 이해하기

Caputchin이 게임을 샌드박싱하는 방법

Caputchin 게임은 당신의 방문자 브라우저에서, 당신의 페이지에서 도는 제3자 코드입니다. 그것이 마켓플레이스에서 오든 당신이 직접 호스팅하든, Caputchin은 그것을 기본으로 신뢰되지 않는 것으로 다루고 여러 독립 격리 계층으로 감싸니, 버그가 있거나 적대적인 게임도 렌더링하고, 플레이하고, 결과를 보고할 수 있지만, 그 밖에는 아무것도 닿을 수 없습니다: 당신의 페이지도, 당신의 방문자 데이터도, 네트워크도.

이 페이지는 모든 조치, 각각이 왜 존재하는지, 그리고 그 전체가 당신 자신의 사이트에 더하는 CSP와 어떻게 상호작용하는지 설명합니다.

한 줄로 된 위협 모델

게임은 제3자가 공급한 임의의 JavaScript(그리고 어쩌면 WebAssembly)를 돌립니다. 따라서 격리 목표는: 게임은 연산하고 그릴 수 있고, 결과를 위젯에 돌려줄 수 있지만, 자기 프레임 바깥의 어떤 것도 읽거나 영향을 줄 수 없다. 아래 모든 계층이 그 하나의 목표를 섬기며, 그것들은 심층 방어입니다, 어떤 단일 계층도 완벽하다고 신뢰되지 않습니다.

계층 1: 불투명 오리진 샌드박스 iframe

모든 게임은 위젯이 일부러 최소한의 sandbox 속성으로 짓는 <iframe> 안에서 돕니다. 부여되는 유일한 토큰은 allow-scripts인데, 게임이 JavaScript이고 돌아야 하기 때문입니다. 그 밖의 모든 것은 보류되며, 가장 중요한 누락은 allow-same-origin입니다.

allow-same-origin 없이 브라우저는 프레임에 고유한 null 오리진을 줍니다. 그 하나의 사실이 하중을 견디는 경계입니다:

  • 게임은 당신 페이지의 DOM, 쿠키, localStorage, 또는 Caputchin 세션을 읽을 수 없습니다, 그것은 당신의 것과 낯선 일회용 오리진에 봉인되어 있습니다.
  • 프레임은 또한 당신의 최상위 창을 결코 탐색하거나, 팝업을 열거나, 폼을 제출하거나, 네이티브 다이얼로그를 띄울 수 없으므로(그 모든 역량은 Caputchin이 부여하지 않는 샌드박스 토큰입니다), 게임에서 당신의 페이지로 도로 나가는 경로가 없습니다.

**allow-same-origin 없는 allow-scripts**의 조합이 요점 전체입니다: 브라우저는 게임의 코드를 실행하지만 프레임을 당신의 것을 아무것도 건드릴 수 없는 낯선 오리진으로 다룹니다. Caputchin은 게임 프레임에 결코 allow-same-origin을 더하지 않습니다. (그 결과로, 게임이 위젯에 post하는 모든 메시지는 오리진 "null"에서 도착하며, 위젯의 채널 확인이 그것을 기대합니다, null이 아닌 오리진은 그 자체로 잘못 구성된 샌드박스를 신호할 것입니다.)

계층 2: 프레임의 문서는 가져와지는 게 아니라 인라인으로 지어짐

위젯은 iframe을 원격 페이지로 향하게 하지 않습니다. 그것은 프레임의 전체 HTML 문서를 인라인으로(srcdoc를 통해) 구성해 null 오리진 프레임에 건넵니다. 그 문서는 작습니다: 엄격한 CSP 메타 태그(다음 계층), 작은 Caputchin 런타임 부트스트랩, 그리고 게임 번들을 로드하는 하나의 <script> 태그.

이것은 두 전달 경로 모두에 같은 기제이며, 번들 URL만 다릅니다:

게임 소스인라인 문서의 번들 URL
마켓플레이스 (플랫폼 해소)Caputchin이 마운트 시 해소한, 고정되고 무결성 해시된 번들 URL.
자체 호스팅 (당신의 game-src)당신이 공급한 URL.

문서가 게임이 아니라 위젯에 의해 작성되므로, 게임은 CSP도, 런타임도, 프레임의 구조도 결코 제어하지 않으며, 로드된 뒤 자기 번들이 하는 것만 제어합니다.

계층 3: 마켓플레이스 게임을 위한 Subresource Integrity

Caputchin이 마켓플레이스 게임을 낼 때 그것은 번들을 불변 버전으로 고정하고 그것의 암호 해시(SHA-384)를 기록합니다. 번들을 로드하는 <script> 태그는 그 해시를 crossorigin="anonymous"와 함께 integrity 속성으로 지니니, 단 한 바이트라도 고정된 것과 다르면 브라우저 자체가 번들 실행을 거부합니다. 손상된 CDN은 다른 코드를 대체할 수 없습니다; 로드가 닫힌 채 실패합니다.

자체 호스팅 게임에는 플랫폼이 주장하는 해시가 없으니(당신이 당신 자신의 바이트의 신뢰 뿌리입니다), integrity 속성은 그 경로에서 그저 생략됩니다. 마켓플레이스 게임의 결과가 서버에서 독립적으로 다시 도출되는 방식, 무결성과는 별개의 보장은 리플레이 계약을 보세요.

계층 4: 엄격한 인라인 Content-Security-Policy

인라인 문서는 빡빡한 Content-Security-Policy를 지닙니다. 프레임이 이미 null 오리진이고 샌드박스됐어도, CSP는 로드된 코드가 무엇을 할 수 있는지 더 옥죕니다, 그것은 기본으로 모든 것을 거부하고 최소한만 다시 부여합니다:

지시어
default-src'none'아래에서 명시적으로 허용되지 않은 모든 것을 거부.
script-srcCaputchin 자체 인라인 런타임의 해시 + 게임 번들의 오리진 + 'wasm-unsafe-eval'Caputchin의 정확한 부트스트랩('unsafe-inline'아니라 sha256- 해시로 고정)과 게임 자체의 번들만 실행. 'wasm-unsafe-eval'은 WASM 엔진이 전체 'unsafe-eval'을 부여하지 않고 컴파일하게 함.
connect-src'none'빼내기 방지 지시어. 게임은 어디로도 fetch, XHR, WebSocket 열기, 또는 비콘을 할 수 없음. 네트워크 출구 전혀 없음.
img-srcdata: (더해 모든 스킨 자산 오리진, 아래)스프라이트는 인라인, 또는 허용된 자산 호스트에서.
media-srcdata: (더해 모든 스킨 자산 오리진, 아래)오디오/비디오는 인라인, 또는 허용된 자산 호스트에서.
font-srcdata:인라인 폰트만.
style-src'unsafe-inline'게임은 인라인 스타일을 설정; 외부 스타일시트 없음. (스타일은 스크립트나 네트워크처럼 데이터를 빼낼 수 없음.)

순효과: 게임은 돌고, 렌더링하고, SDK 브리지를 통해 결과를 보고하며, 그 밖에는 아무것도, 특히 네트워크에는 닿을 수 없습니다. 이 CSP는 Caputchin이 설정하며 당신이 구성하는 것이 아닙니다; 게임이 정확히 얼마나 갇혀 있는지 당신이 이해하도록 여기 나열되어 있습니다.

고객 설정이 프레임 CSP를 넓히는 한 곳

스킨은 이미지나 오디오 필드를 당신 자신의 CDN의 절대 URL로 가리킬 수 있습니다(스킨을 보세요). 그 자산이 잠긴 프레임 안에서 로드되려면, Caputchin은 프레임의 img-src / media-src그 정확한 자산 오리진만 더하고, 그 밖에는 어디에도 더하지 않습니다. script-srcconnect-src는 결코 넓혀지지 않으니, 허용된 자산 오리진이라도 코드를 로드하거나 네트워크 채널을 여는 데 쓸 수 없습니다. 이것이 구성된 값이 프레임의 정책에 영향을 주는 단 하나의, 좁은 방법이며, 그것도 여전히 자산뿐입니다.

계층 5: 단방향 결과 채널

게임은 당신의 페이지로 호출 가능한 표면이 없습니다. 나가는 유일한 방법은 SDK 브리지입니다: 게임은 당신의 오리진에 사는 위젯으로 자기 불투명 결과(그 트레이스)를 postMessage하는 단일 메서드를 호출합니다. 위젯이 Caputchin의 API와 이야기하는 것입니다; 게임은 결코 그러지 않습니다(그럴 수 없습니다, connect-src'none'입니다). 그러니 신뢰 경로는 게임 → 위젯 → 당신의 백엔드이고, 각 도약은 결과를 앞으로만 넘기지, 결코 게임에 뒤로의 도달을 부여하지 않습니다.

당신 자신의 페이지에 설정하는 CSP

위 계층은 당신과 당신의 방문자를 게임으로부터 보호합니다. 당신 자신의 페이지의 Content-Security-Policy는 다른, 보완하는 통제입니다: 그것은 당신의 페이지를 모든 것으로부터 보호하고, Caputchin은 엄격한 것 아래에서 돌도록 설계되었습니다. Caputchin을 임베드하려고 CSP를 느슨하게 할 필요는 없습니다; 위젯이 정당하게 쓰는 몇 개의 오리진을 허용하면 됩니다.

최소한, 위젯에 필요한 것:

지시어허용
script-src당신이 위젯 스크립트를 로드하는 오리진, 더해 'unsafe-eval'<caputchin-widget> / <caputchin-game>을 정의하는 <script>, 당신이 고른 CDN(jsDelivr, 당신 자신의 호스트, 또는 caputchin.com). 'unsafe-eval'계측 챌린지가 돌게 함; 계측이 켜진 동안 필수이며, 키의 보안 페이지에서 계측을 꺼서 떨굴 수 있음.
connect-srchttps://caputchin.com위젯은 검증을 세우고 확인하려고 Caputchin API를 호출. 위젯을 다른 API 호스트로 향하게 하면, 대신 그것을 허용.
frame-srchttps://caputchin.com게임 iframe을 다스림. 프레임이 인라인 srcdoc 문서를 쓰므로, 브라우저가 당신의 frame-src를 그것에 적용하니, 여기 Caputchin 오리진을 허용.
worker-srcblob:proof-of-work 풀이기는 전적으로 blob: URL에서 만들어진 Web Worker에서 돌고, 메인 스레드 대체가 없으니, 이것은 필수. worker-src를 생략하면, 브라우저는 child-src 다음 default-src로 물러나고, default-src 'self'만으로는 blob:을 허용하지 않음.

선택적으로 script-src'wasm-unsafe-eval'을 더하세요: 그것은 proof-of-work 풀이기가 빠른 WebAssembly로 돌게 합니다. 필수는 아니며, 그것 없이 풀이기는 더 느린 순수 JavaScript 구현(여전히 Worker 안에서)으로 물러납니다.

당신의 페이지 CSP에서 게임 자체의 번들 오리진(jsDelivr, 게임의 CDN, 당신의 game-src 호스트)을 허용할 필요는 없습니다: 그 번들은 위에서 설명한 프레임 자체의 CSP 아래, 샌드박스된 프레임 안에서 로드되지, 당신 페이지의 정책 아래가 아닙니다. 당신의 페이지는 Caputchin을 프레임할 뿐입니다; Caputchin이 안에서 도는 것을 가둡니다.

Caputchin 요소가 당신의 CSP 아래에서 조용히 로드에 실패하면, 당신의 브라우저 콘솔이 차단된 지시어의 이름을 댑니다; 그것이 대는 오리진이나 키워드를 그 지시어에 더하세요. 엄격하게 시작하고 콘솔이 청하는 것만 정확히 여세요. 당신은 'unsafe-inline'이 결코 필요 없습니다. 워커를 위해 blob:(worker-src)이, 그리고 계측이 켜진 동안 script-src'unsafe-eval'이 필요합니다; 'unsafe-eval' 요건은 키의 보안 페이지에서 계측을 끄면 사라집니다. 'wasm-unsafe-eval'은 선택입니다(그것은 proof-of-work 풀이기를 빠르게 하며, 그것 없이는 같은 Worker 안에서 JavaScript로 더 느리게 돕니다).

왜 이렇게 많은 계층인가

각 계층은 그 자체로 의미 있는 경계일 것입니다; 함께 그것들은 하나의 실패가 침해가 아니라는 뜻입니다. null 오리진만으로도 이미 게임을 당신의 데이터로부터 벽으로 막고; CSP만으로도 이미 네트워크 출구를 죽이고; 무결성만으로도 이미 정확한 바이트를 고정합니다. Caputchin은 그 모두를 돌리는데, 신뢰되지 않는 제3자 코드가 바로 심층 방어가 제값을 하는 곳이기 때문입니다.

함께 보기

이 페이지에서