~13 min · side-panel, csp, iframe, frame-src, web-accessible-resources
Level 0Extension 입덕
0 XP0/54 lessons0/13 achievements
0/100 XP to next level100 XP to go0% complete
"Side panel 은 그냥 extension HTML page, popup 을 다스리는 같은 MV3 content security policy 가 다스려. Lesson 5 는 규칙과 안전한 escape valve — 뭘 직접 렌더 가능, 뭐가 iframe 필요, hole 안 만들고 frame-src 넓히는 법."
Default extension-pages CSP
MV3 가 extension 안 모든 HTML page (popup, side panel, options page, full-tab page) 에 strict default Content Security Policy 와 함께 ship:
script-src 'self'; object-src 'self';
허용하는 것:
Extension 에 bundle 된 JavaScript file (<script src="panel.js">).
Extension 에 bundle 된 stylesheet.
이미지 / font / 대부분의 다른 passive resource 는 어디서든.
Fetch / XHR 은 어떤 URL 로든.
금지하는 것:
Inline script (<script>...</script>) 와 inline event handler (onclick="foo()").
eval, new Function, string argument 가진 setTimeout — 다 runtime 에 ban.
Extension 바깥 어디서든 <script src="https://cdn.example.com/lib.js"> load.
Non-extension URL 가리키는 <iframe> — CSP 안 넓히면 차단.
Remote-script ban 이 MV3 의 flagship 보안 변경. Iframe block 은 side panel 에 third-party content embed 시도할 때 가장 먼저 무는 거.
CSP 넓히기 — frame-src
Panel 에 iframe 허용하려면 manifest 에 content_security_policy.extension_pages entry 추가. 형식은 single CSP string; script-src 와 object-src baseline 다시 진술하고 frame-src 추가:
이제 <iframe src="https://www.youtube.com/embed/..."> 가 panel.html 안에서 동작. 다른 origin 은 여전히 차단. List 를 가능한 한 tight 하게 유지 — frame-src 의 모든 domain 이 그 site 가 나중에 compromise 되면 잠재 공격 surface.
흔한 use case
문서나 help content. Domain 제어하는 곳에 host 된 자체 docs 렌더; extension 안에 help text bundle 하고 update 하는 것보다 저렴.
Authentication redirect. 일부 auth flow 가 third-party identity provider 통해 redirect; iframe 패턴이 새 tab spawn 없이 panel 안에서 redirect 처리.
Sandboxed extension content. 자체 chrome-extension:// page (다른 path 가진) 가리키는 iframe 이 민감 코드 wall off — user-provided HTML/markdown 표시할 때 script-of-self 권한 없이.
제어하는 page sandbox
마지막 케이스 — untrusted user content 렌더링 — 엔 extension iframe 과 sandbox manifest key 결합:
{
"sandbox": {
"pages": ["sandbox.html"]
}
}
sandbox.html 이 chrome.* API access 없이 unique origin 에서 돔. 부모 panel 이 거기 postMessage 가능, 안의 어떤 코드도 user clip storage 닿을 수 없다고 신뢰. Source content 가 본질적으로 임의인 rich markdown 이나 HTML clip 표시 패턴.
Web accessible resources — 역방향
위 iframe 이야기는 panel 이 외부 content load 하는 것. 역방향 — host page 가 extension page embed 하게 허용 — 은 web_accessible_resources 사용:
List 된 origin 이 어떤 extension file load 허용되는지 선언. Extension file 가리키는 <script> 태그 inject 하는 content script (Lesson 3 의 legacy bridge 패턴) 와 page 가 extension iframe embed 하게 허용하는 extension 에서 사용.
Default CSP 가 일부러 tight. 필요한 것만 추가. Inline event handler, eval, 임의 iframe origin 이 design 으로 차단 — underlying 패턴 fix, CSP disable 시도 안 함.
'unsafe-eval' 추가 안 함. Chrome Web Store 가 'unsafe-eval' 이나 'unsafe-inline' 로 CSP 느슨하게 한 extension 을 거부. 드문 정당한 이유 (옛 bundler 의 eval-based loader 통한 WebAssembly) 도 거의 항상 현대 우회로 있음. Eval 필요해 보이면, dependency 가 잘못된 build target 고른 거 — 그걸 fix.
Code
manifest.json — frame-src 가진 extension_pages CSP, plus sandbox page·json
clipdeck/manifest.json 을 첫 번째 code block 으로 update (version 0.7.0, content_security_policy.extension_pages 가 frame-src 에 https://docs.example.com 허용 위해 넓혀짐; sandbox.pages 선언). 두 번째 code block 의 iframe markup 을 clipdeck/panel.html 에 추가. Placeholder sandbox.html 생성: <h1 id="out">sandbox alive</h1><script>parent.postMessage({source:'clipdeck-sandbox', type:'rendered', heightPx:40}, '*');</script>. Extension reload 하고 side panel 열기 — docs iframe 은 placeholder error page 표시 (docs.example.com 은 실제 host 아님), sandbox iframe 이 load 되고 postMessage 보냄. Panel DevTools 의 network tab 열어 docs.example.com 요청 허용된 거 확인; 아니면 CSP error 로깅됐을 거. CSP 가 동작 증명하려면 iframe src 를 https://example.com/anything (frame-src 에 없음) 으로 바꾸고 reload — iframe 이 console 의 명확한 CSP violation 과 함께 차단됨.
Hint
Panel DevTools console 이 manifest update 후에도 Refused to frame ... because it violates the following Content Security Policy directive: frame-src 'self' 보고하면, 두 가지 흔한 원인: (1) manifest 편집 후 extension reload 안 함, 또는 (2) manifest JSON 이 문법적으로 깨져 Chrome 이 silently default 로 fallback (chrome://extensions → Errors 확인). Sandbox.html 이 아예 load 안 되면 sandbox.pages 아래 list 됐고 extension 디렉토리의 실제 파일인지 확인. Sandbox postMessage 가 sandbox.js 가 chrome.* access 시도하면 silently fail — sandbox page 는 chrome.* API access 없음, 그게 point.
Progress
Progress is local-only — sign in to sync across devices.