한줄 요약
iframe 샌드박스 + CSP 조합으로 신뢰할 수 없는 HTML 앱을 안전하게 실행하는 Datasette Apps 플러그인이 공개됐다.
무엇이 달라지나?
Datasette는 SQLite 기반 데이터 탐색 도구로, 오래전부터 JSON API를 통해 커스텀 프론트엔드를 붙일 수 있었다. 이번에 공개된 datasette-apps 플러그인은 그 방식을 한 단계 끌어올린다. HTML+JavaScript로 작성된 독립 앱을 Datasette 내부에 직접 호스팅할 수 있게 된 것이다.
핵심 메커니즘은 <iframe sandbox="allow-scripts allow-forms" srcdoc="..."> 조합이다. 이 설정만으로도 자식 iframe은 부모 DOM에 접근하거나, 쿠키를 읽거나, localStorage를 건드릴 수 없다. 그런데 여기서 한 가지 구멍이 남는다. fetch()를 통한 외부 도메인 요청은 여전히 가능하기 때문이다. 악의적이거나 버그가 있는 앱이 민감한 데이터를 외부로 전송할 수 있는 경로가 열려 있다.
이 구멍을 막는 것이 <meta http-equiv="Content-Security-Policy"> 태그다. HTML 문서 최상단에 이 태그를 삽입하면, 외부 도메인으로의 HTTP 요청이 원천 차단된다. 흥미로운 점은 악성 JavaScript가 이 태그를 제거하거나 수정하려 해도 CSP는 이미 적용된 이후라 변경이 불가능하다는 것이다. 한번 선언된 CSP 정책은 해당 프레임 내에서 불변(immutable)이다.
앱이 격리됐다면, 데이터와는 어떻게 통신하는가. 처음에는 postMessage()로 부모 창에 SQL 쿼리 실행을 요청하는 단순한 프로토콜을 설계했다. 이후 GPT-5.5의 조언을 참고해 MessageChannel() 기반 방식으로 전환했다. MessageChannel()은 페이지 이동이 발생하면 채널이 자동으로 닫히는 특성이 있어, 신뢰할 수 없는 외부 페이지가 채널을 가로채 명령을 실행하는 시나리오를 원천 차단한다.
쓰기 쿼리도 지원한다. 별도로 구성된 저장 쿼리(stored queries)와 연동하면 읽기뿐 아니라 데이터 변경도 앱 내에서 처리할 수 있다. 이 구조 덕분에 Datasette Apps는 단순 대시보드가 아닌 데이터 입력·수정 도구로도 활용이 가능하다.
오류 가시성도 챙겼다. iframe 내부에서 CSP 위반 등 에러가 발생하면, 해당 에러는 부모 프레임으로 전송되어 로그 형태로 표시된다. 개발자가 앱을 디버깅할 때 브라우저 콘솔이 아니라 Datasette UI 안에서 문제를 확인할 수 있다.
실무에서 어떤 의미인가?
이 설계가 흥미로운 이유는 기술 자체보다 '패턴'에 있다. 격리된 실행 환경 + 허용 목록 기반 API 통로 + 불변 보안 정책이라는 조합은, 멀티테넌트 SaaS나 내부 어드민 도구를 만들 때 그대로 적용할 수 있는 구조다.
Claude Artifacts에 영감을 받아 시작했다고 알려진 이 프로젝트는, AI가 생성한 코드를 안전하게 실행하는 샌드박스로도 읽힌다. LLM이 HTML+JavaScript 앱을 생성하고, 그 앱이 실제 데이터베이스와 통신하는 흐름-Datasette Apps는 그 흐름을 하나의 플랫폼 위에 올려놓는다.
데이터를 다루는 내부 도구나 어드민 페이지를 개발할 때, 보안 격리 없이 동일 도메인에서 여러 앱을 실행하는 구조는 잠재적 위험을 안고 간다. iframe 샌드박스 패턴은 그 위험을 줄이는 현실적인 선택지 중 하나다. 외주 개발이나 내부 개발 모두 이 패턴을 참고할 만하다.
도입 전 체크포인트
호스팅 환경 확인. datasette-apps는 Datasette 플러그인이므로 Datasette 인스턴스가 필요하다. agent.datasette.io에서 GitHub 로그인으로 데모를 먼저 확인할 수 있다.
CSP allow-list 설계. 기본 CSP는 외부 이미지 도메인도 차단한다. 앱에서 외부 리소스를 사용할 계획이라면, 허용할 도메인 목록을 미리 정의해야 한다. 정의하지 않으면 에러 로그에 해당 도메인이 표시되는 방식으로 확인할 수 있다.
쓰기 쿼리 범위 설계. 읽기 전용 기본 설정 외에 데이터 변경이 필요하다면 저장 쿼리를 별도로 구성해야 한다. 어떤 테이블에 어떤 조작을 허용할지를 앱 개발 초기에 설계하는 것이 나중에 리팩터링 비용을 줄인다.
보안 경계 명확화. iframe 샌드박스는 강력하지만 만능이 아니다. 앱 자체의 로직 결함이나 SQL 인젝션 가능성은 별도로 검토해야 한다.