더 알아보기

리소스 참조

확장앱은 내부에 확장앱 페이지를 포함하여 CSS, 이미지, 오디오, 동영상 등 웨일 브라우저에서 사용할 수 있는 다양한 리소스 파일을 포함할 수 있습니다. 각각의 리소스 파일은 whale-extension://<확장앱_ID>/경로/파일명 형태의 주소를 갖습니다. 확장앱 ID는 확장앱 관리자(whale://extensions/)에서 해당 확장앱 정보의 개발자 도구 탭에서 확인할 수 있습니다.

확장앱 아이디

웨일 스토어에 등록되지 않은 개발 단계의 확장앱은 설치하는 기기마다 ID가 달라질 수 있습니다. 확장앱 페이지 주소 혹은 리소스 주소를 얻어야 하는 경우 직접 문자열 조합으로 구성하기보다 whale.runtime.getURL() API를 이용하는 것이 안전합니다.

// whale-extensions://<확장앱_ID>/path/index.html 페이지가 새 탭으로 열립니다
const url = whale.runtime.getURL(`path/index.html`);
whale.tabs.create({ url });

확장앱 페이지에서 이미지, CSS, JS/JSON 등의 확장앱 리소스를 사용하려면 매니페스트에 해당 리소스 경로를 web_accessible_resources 항목에 정의해야 합니다. 경로와 파일 이름에 와일드카드를 사용하여 일정한 패턴을 가진 여러 파일을 간단히 추가할 수 있습니다.

{
...
"web_accessible_resources": [
"style/sheet.css",
"images/*.png",
"fonts/*"
]
...
}

이렇게 정의한 경로의 파일들은 유효한 CORS 헤더와 함께 제공되며, 이것은 확장앱 페이지 내에서 XMLHttpRequest 혹은 fetch API 로 활용할 수 있다는 뜻입니다. 정의되지 않은 리소스는 whale-extension://... 주소를 직접 입력하더라도 접근할 수 없습니다. 콘텐츠 스크립트 혹은 백그라운드 페이지로 정의한 파일들은 web_accessible_resources에 등록하지 않아도 됩니다.

안전한 확장앱 만들기

확장앱은 매니페스트 설정을 통해 일반적인 웹 어플리케이션과는 다른 특별한 권한을 부여받기 때문에 흔히 생각하는 것 이상의 많은 것을 할 수 있습니다. 때문에 확장앱의 보안이 취약하면 이 확장앱을 사용하는 모든 사용자들이 악의적인 공격에 노출될 수 있습니다. Stay Secure에 소개된 항목들을 지키는 안전한 확장앱을 만들어주세요.

  • 모든 네트워크 요청은 HTTPS를 사용해주세요. HTTP 연결은 중간자 공격에 취약하여 언제든 위·변조 될 수 있습니다.
  • 사이트간 스크립팅 공격(XSS)에 사용될 수 있는 함수는 사용하지 않는 것이 좋아요.
  • 콘텐츠 스크립트는 확장앱이 웹 페이지와 상호 작용하는 유일한 통로입니다. 삽입된 페이지의 DOM을 참조하여 정보를 처리하는 과정에서 예상치 못한 위험에 노출될 수 있습니다. 민감한 작업은 백그라운드 페이지와 같은 독립된 프로세스에서 수행하는 것이 안전해요.
  • 매니페스트에 외부 연결은 신뢰할 수 있는 상대에게만 최소한으로 허용해주세요.
  • 매니페스트에 권한은 꼭 필요한 것만 최소한으로 부여해주세요.
  • 매니페스트에 명시적인 콘텐츠 보안 정책을 설정하세요.

콘텐츠 보안 정책

콘텐츠 보안 정책(Content Security Policy, CSP)은 사이트간 스크립팅 공격(XSS)을 방어하기 위한 것으로, 해당 페이지에서 사용할 수 있는 리소스를 각 형태별 화이트리스트로 정의하는 방식입니다. 일반적인 웹 페이지에서는 서버에서 Content-Security-Policy 헤더를 전송하도록 설정하는데, 확장앱은 매니페스트의 content_security_policy 항목으로 설정합니다. 확장앱 페이지에 접속하여 개발자 도구를 열고 네트워크 패널을 확인해 보면 마치 서버에서 제공하는 것과 같이 Content-Security-Policy 헤더가 설정되어 있는 것을 확인할 수 있습니다.

매니페스트에 content_security_policy 항목을 설정하지 않은 경우 기본 설정은 script-src 'self'; object-src 'self' 입니다. 이 설정이 주는 제약사항은 아래와 같습니다:

  • JS evaluation 구문이 실행되지 않습니다.
    // 실행되지 않음
    alert(eval("test"));
    window.setTimeout("alert('test')", 10);
    window.setInterval("alert('test')", 10);
    new Function("return test");
  • 인라인 스크립트(inline-script)가 실행되지 않습니다.
    <!-- 실행되지 않음 -->
    <body>
    <button onclick="console.log('test')">
    <script>console.log("test");</script>
    </body>
  • <script> 를 포함한 스크립트 요소<object>, <embed>, <applet> 등 객체 요소가 확장앱 패키지 내부의 리소스만 사용할 수 있도록 제한됩니다.
    <!-- 실행되지 않음 -->
    <script src="https://somewhere.safe.com/trusted.js"></script>

이 항목을 default-src 'self'로 설정하면 확장앱 페이지에서 위 요소 뿐 아니라 이미지, CSS를 포함한 모든 리소스가 확장앱 내부의 리소스만 참조할 수 있도록 제한할 수 있습니다. 원격 리소스를 참조할 일이 없다면 명시적으로 가장 폐쇄적인 이 설정을 권합니다.

이 항목에 URL 주소 패턴을 이용해 원격 리소스를 제한적으로 허용할 수 있습니다. 단, https, blob, filesystem 주소만 설정할 수 있습니다. 예를 들어 아래와 같은 설정은 스크립트 요소에 https://www.naver.com/ 으로 시작하는 주소의 리소스를 사용할 있다는 뜻입니다.

{
...
"content_security_policy": "script-src 'self' https://www.naver.com; object-src 'self'"
...
}

이 설정은 확장앱 페이지를 위한 것으로 콘텐츠 스크립트는 영향을 받지 않습니다.
콘텐츠 스크립트는 삽입된 해당 페이지에 적용된 콘텐츠 보안 정책을 따릅니다.

테스트와 디버깅

확장앱 개발 단계에서는 웨일 스토어에 등록하지 않고 개발자 모드로 설치하여 테스트하며 디버깅을 진행할 수 있습니다.
구현 예제의 테스트와 디버깅을 참고하세요.