보안 모델
This content is not available in your language yet.
Suji가 frontend(renderer)에서 backend로 향하는 모든 호출에 적용하는 보안 정책. Electron 모델과 동등한 곳, 다른 곳을 정확히 구분한다.
노출 surface (V8 binding)
섹션 제목: “노출 surface (V8 binding)”window.__suji__ 오브젝트에 노출되는 것:
| 항목 | 종류 | 비고 |
|---|---|---|
invoke(backend, request) | native (V8 binding) | backend cmd 호출, Promise<JSON> |
emit(event, data) | native (V8 binding) | EventBus 브로드캐스트 |
core(request) | JS helper | invoke("__core__", ...) shorthand |
on(event, cb) / off(event, cb) | JS helper | EventBus listener |
platform | string 상수 | `“macos" |
Electron 비교: Electron의 contextIsolation: true는 preload script만 main world에
노출. Suji는 모든 surface를 main world의 window.__suji__에 직접 바인딩 (Electron의
contextIsolation:false 동등). 노출 surface가 매우 작아 (invoke + emit 2개 native만)
실제 위험은 cmd-level 정책에 의존한다.
로드맵: Electron-style contextBridge isolated world 분리. 현재는 surface가 작고 fs/cache 격리로 대부분의 위험을 차단하고 있어 우선순위가 낮다.
fs sandbox
섹션 제목: “fs sandbox”frontend가 호출하는 fs.* cmd는 path 화이트리스트 + traversal 가드로 검증.
fs.mdx 참고.
{ "fs": { "allowedRoots": ["~/Documents/myapp"] } }| 보호 | 동작 |
|---|---|
| Default safe | allowedRoots 미설정/빈 배열 → 모든 frontend fs.* 차단 |
| Path traversal | .. path component는 모든 mode에서 항상 차단 (["*"]도 우회 불가) |
| Prefix-extension 차단 | /foo/bar 허용 시 /foo/barX 통과 X (separator boundary 가드) |
~ 사전 expand | config load 시 1회 — hot path env lookup 0회 |
| Backend 우회 | backend SDK 호출은 무제한 (사용자 자체 코드 신뢰) |
fs.* 외에도 renderer가 file path를 넘기는 native cmd는 같은 경계로 검사한다.
| cmd | sink | 정책 |
|---|---|---|
print_to_pdf / capture_page / desktop_capturer_capture_thumbnail | 파일 쓰기 | fs.allowedRoots 설정 시 enforce |
native_image_get_size / native_image_to_png / native_image_to_jpeg | 파일 읽기/인코딩 | fs.allowedRoots 설정 시 enforce |
tray_create.iconPath | 이미지 파일 로드 | fs.allowedRoots 설정 시 enforce |
이 경로들은 기존 릴리즈에서 무제한이었기 때문에 fs.allowedRoots가 미설정/빈 배열이면 레거시
동작을 유지한다. fs.allowedRoots를 설정한 앱에서는 fs.*와 동일한 traversal/boundary
검사를 적용한다.
shell / dialog allowlist
섹션 제목: “shell / dialog allowlist”shell.*와 dialog open/save의 defaultPath는 opt-in allowlist를 제공한다. 키가 없으면
기존 동작을 유지하고, 키가 있으면 빈 배열은 deny-all, ["*"]는 allow-all, 나머지는
path boundary 또는 URL glob 매치만 허용한다.
{ "shell": { "allowedPaths": ["~/Documents/myapp"], "allowedExternalUrls": ["https://*.example.com/*"] }, "dialog": { "allowedPaths": ["~/Documents/myapp"] }}Backend SDK 호출은 fs sandbox와 동일하게 우회한다.
앱 데이터 / cache 격리
섹션 제목: “앱 데이터 / cache 격리”config.app.name 키로 OS 표준 user-data 디렉토리 아래 자동 격리. 한 시스템에 여러
Suji 앱이 있어도 cookie/localStorage/IndexedDB/Service Worker가 서로 영향 없음.
cache.mdx 참고.
IPC 유효성 검사
섹션 제목: “IPC 유효성 검사”__core__ channel을 통해 들어오는 모든 IPC 메시지가 통과:
| 검증 | 거부 시 응답 |
|---|---|
| payload size ≤ 32KB | error: "payload_too_large" |
cmd 필드 존재 | error: "missing_cmd" |
cmd 영숫자/언더스코어만 | error: "invalid_cmd" (newline/quote 등 injection 차단) |
| 알려진 cmd | unknown 시 error: "unknown_cmd" (typo / version mismatch 진단) |
| cmd 정확 매치 | substring 매치 X |
iframe sandbox / origin allowlist
섹션 제목: “iframe sandbox / origin allowlist”외부 untrusted 콘텐츠 (광고/위젯/임베드)를 iframe으로 띄울 때 origin 화이트리스트로 제한.
production suji:// 응답에 붙는 CSP frame-src directive로 Chromium이 차단한다.
suji.json:
{ "security": { "iframeAllowedOrigins": ["https://trusted.com", "https://api.example.com"] }}| 설정 | 동작 |
|---|---|
미설정 / [] | default block — 모든 iframe 차단 (frame-src 'none') |
["https://trusted.com"] | 해당 origin만 허용 (frame-src 'self' https://trusted.com) |
["*"] | 무제한 escape hatch (frame-src *) — 권장 X |
사용자가 security.csp로 직접 CSP 명시 시 그것 우선 — iframe_allowed_origins은 무시.
그 경우 사용자가 직접 frame-src 명시 책임.
security.csp는 명시 문자열 override와 "disabled" escape hatch를 지원한다. 미설정이면
Suji가 default CSP를 만들고 iframeAllowedOrigins를 frame-src에 반영한다.
macOS App Sandbox
섹션 제목: “macOS App Sandbox”suji build --sandbox 또는 SUJI_SANDBOX로 App Sandbox entitlements를 자동 부착한다.
main app과 CEF Helper(Browser/GPU/Renderer/Plugin)별 plist를 분리하고 helper에는 inherit
entitlement를 적용한다. Security-scoped bookmarks API는 별도 sandbox.mdx에
정리되어 있다.
알려진 한계
섹션 제목: “알려진 한계”- 진짜 isolated world:
window.__suji__surface는 freeze/hardening되어 있지만 Chromium isolated world/contextBridge와 동일한 별도 V8 context는 아직 아니다. - dev mode CSP:
dev_url로 Vite 등 외부 서버를 직접 로드하는 동안에는 Suji가 응답 헤더를 주입하지 않는다. dev 서버나 HTML meta CSP로 별도 검증해야 한다. - network/webRequest:
webRequest는 선언적 blocklist API로 제공한다. renderer 일반 fetch allowlist는 별도 HTTP plugin 정책으로 다룬다. - App Sandbox 실효 검증: 로컬 빌드와 entitlement 부착은 자동화되어 있지만, Mac App Store 심사 환경의 실제 sandbox 검증은 별도 배포 검증이 필요하다.