댓글 검색 목록

[기타] chrome extention - 17. Content Security Policy (CSP)

페이지 정보

작성자 운영자 작성일 20-11-05 10:29 조회 681 댓글 0

많은 종류의 잠재적 인 교차 사이트 스크립팅 문제를 완화하기 위해 Chrome의 확장 시스템은 콘텐츠 보안 정책 (CSP)의 일반 개념을 통합했습니다. 이는 기본적으로 확장을 보다 안전하게 만드는 매우 엄격한 정책을 도입하고 확장 및 애플리케이션에서로드 및 실행할 수 있는 콘텐츠 유형을 관리하는 규칙을 만들고 적용 할 수 있는 기능을 제공합니다.


일반적으로 CSP는 확장 프로그램에서로드하거나 실행하는 리소스에 대한 차단 / 허용 목록 메커니즘으로 작동합니다. 확장 프로그램에 대한 합리적인 정책을 정의하면 확장 프로그램에 필요한 리소스를 신중하게 고려하고 확장 프로그램이 액세스 할 수있는 유일한 리소스인지 브라우저에 요청할 수 있습니다. 이러한 정책은 확장 프로그램이 요청하는 호스트 권한에 대한 보안을 제공합니다. 이는 대체가 아니라 추가 보호 계층입니다.


웹에서 이러한 정책은 HTTP 헤더 또는 메타 요소를 통해 정의됩니다. Chrome의 확장 시스템 내부에서는 둘 다 적절한 메커니즘이 아닙니다. 대신 확장의 정책은 다음과 같이 확장의 manifest.json 파일을 통해 정의됩니다.


{
  ...,
  "content_security_policy": "[POLICY STRING GOES HERE]"
  ...
}

CSP의 구문에 대한 자세한 내용은 콘텐츠 보안 정책 사양 및 HTML5Rocks의 "콘텐츠 보안 정책 소개"문서를 참조하세요.


기본 정책 제한 


manifest_version을 정의하지 않는 패키지에는 기본 콘텐츠 보안 정책이 없습니다. manifest_version 2를 선택하는 사용자는 다음과 같은 기본 콘텐츠 보안 정책을 갖습니다.

script-src 'self'; object-src 'self'

이 정책은 다음 세 가지 방법으로 확장 및 응용 프로그램을 제한하여 보안을 추가합니다.


평가 및 관련 기능이 비활성화 됨 


다음과 같은 코드가 작동하지 않습니다.

alert(eval("foo.bar.baz"));
window.setTimeout("alert('hi')", 10);
window.setInterval("alert('hi')", 10);
new Function("return foo.bar.baz");

이와 같은 JavaScript 문자열을 평가하는 것은 일반적인 XSS 공격 벡터입니다. 대신 다음과 같은 코드를 작성해야 합니다.

alert(foo && foo.bar && foo.bar.baz);
window.setTimeout(function() { alert('hi'); }, 10);
window.setInterval(function() { alert('hi'); }, 10);
function() { return foo && foo.bar && foo.bar.baz };

인라인 JavaScript가 실행되지 않습니다. 


인라인 JavaScript는 실행되지 않습니다. 이 제한은 인라인 <script> 블록과 인라인 이벤트 핸들러 (예 : <button onclick = "...">)를 모두 금지합니다.


첫 번째 제한은 악의적 인 제 3자가 제공 한 스크립트를 실수로 실행할 수 없도록 함으로써 엄청난 종류의 교차 사이트 스크립팅 공격을 제거합니다. 그러나 콘텐츠와 동작을 명확하게 구분하여 코드를 작성해야 합니다 (물론 그래야 합니다). 예를 들어 이를 더 명확하게 할 수 있습니다. 다음을 포함하는 단일 popup.html로 브라우저 액션의 팝업을 작성하려고 할 수 있습니다.

<!doctype html>
<html>
  <head>
    <title>My Awesome Popup!</title>
    <script>
      function awesome() {
        // do something awesome!
      }

      function totallyAwesome() {
        // do something TOTALLY awesome!
      }

      function clickHandler(element) {
        setTimeout("awesome(); totallyAwesome()", 1000);
      }

      function main() {
        // Initialization work goes here.
      }
    </script>
  </head>
  <body onload="main();">
    <button onclick="clickHandler(this)">
      Click for awesomeness!
    </button>
  </body>
</html>

이 작업을 예상대로 작동하려면 세 가지 사항을 변경해야 합니다.

  • clickHandler 정의는 외부 JavaScript 파일로 이동해야 합니다 (popup.js가 좋은 대상이 됨).
  • 인라인 이벤트 핸들러 정의는 addEventListener 측면에서 다시 작성하고 popup.js로 추출해야 합니다. 
    현재 <body onload = "main ();">과 같은 코드를 통해 프로그램 실행을 시작하는 경우 필요에 따라 문서의 DOMContentLoaded 이벤트 또는 창의 로드 이벤트에 연결하여 대체하는 것이 좋습니다. 아래에서는 일반적으로 더 빨리 트리거 되므로 전자를 사용합니다.
  • setTimeout 호출은 "awesome(); totallyAwesome()"문자열을 실행을 위해 JavaScript로 변환하지 않도록 다시 작성해야 합니다.

이러한 변경 사항은 다음과 같습니다.

function awesome() {
  // Do something awesome!
}

function totallyAwesome() {
  // do something TOTALLY awesome!
}

function awesomeTask() {
  awesome();
  totallyAwesome();
}

function clickHandler(e) {
  setTimeout(awesomeTask, 1000);
}

function main() {
  // Initialization work goes here.
}

// Add event listeners once the DOM has fully loaded by listening for the
// `DOMContentLoaded` event on the document, and adding your listeners to
// specific elements when it triggers.
document.addEventListener('DOMContentLoaded', function () {
  document.querySelector('button').addEventListener('click', clickHandler);
  main();
});
<!doctype html>
<html>
  <head>
    <title>My Awesome Popup!</title>
    <script src="popup.js"></script>
  </head>
  <body>
    <button>Click for awesomeness!</button>
  </body>
</html>

로컬 스크립트 및 개체 리소스 만 로드됩니다. 


스크립트 및 개체 리소스는 웹 전체가 아닌 확장 프로그램의 패키지에서만 로드 할 수 있습니다. 이렇게 하면 확장 프로그램이 특별히 승인 한 코드 만 실행하여 활성 네트워크 공격자가 리소스에 대한 요청을 악의적으로 리디렉션 하지 못하도록 합니다.


외부 CDN에서 로드 되는 jQuery (또는 다른 라이브러리)에 의존하는 코드를 작성하는 대신 확장 패키지에 특정 버전의 jQuery를 포함하는 것이 좋습니다. 즉, 대신 :

<!doctype html>
<html>
  <head>
    <title>My Awesome Popup!</title>
    <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
  </head>
  <body>
    <button>Click for awesomeness!</button>
  </body>
</html>

파일을 다운로드하고 패키지에 포함하고 다음을 작성하십시오.

<!doctype html>
<html>
  <head>
    <title>My Awesome Popup!</title>
    <script src="jquery.min.js"></script>
  </head>
  <body>
    <button>Click for awesomeness!</button>
  </body>
</html>

기본 정책 완화 


Inline Script 


Chrome 45까지는 인라인 JavaScript 실행에 대한 제한을 완화하는 메커니즘이 없었습니다. 특히 'unsafe-inline'을 포함하는 스크립트 정책을 설정해도 효과가 없습니다.


Chrome 46부터는 정책에서 소스 코드의 base64 인코딩 해시를 지정하여 인라인 스크립트를 허용 할 수 있습니다. 이 해시는 사용 된 해시 알고리즘 (sha256, sha384 또는 sha512)으로 시작해야 합니다. 예제는 <script> 요소에 대한 해시 사용을 참조하십시오.


Remote Script 


일부 외부 JavaScript 또는 개체 리소스가 필요한 경우 스크립트를 허용해야 하는 보안 출처를 나열하여 정책을 제한적으로 완화 할 수 있습니다. 확장 프로그램의 상승 된 권한으로 로드 된 실행 가능 리소스가 예상 한 리소스와 정확히 일치하고 활성 네트워크 공격자로 대체되지 않았는지 확인하고자 합니다. man-in-the-middle 공격은 사소하고 HTTP를 통해 탐지 할 수 없으므로 이러한 출처는 허용되지 않습니다.


현재 개발자는 blob, 파일 시스템, https 및 chrome-extension 스키마를 사용하여 원본을 허용 할 수 있습니다. https 및 chrome-extension 체계에 대해 오리진의 호스트 부분을 명시 적으로 지정해야 합니다. https :, https : // * 및 https : //*.com과 같은 일반 와일드 카드는 허용되지 않습니다. https : //*.example.com과 같은 하위 도메인 와일드 카드가 허용됩니다. 공용 접미사 목록의 도메인도 일반 최상위 도메인으로 간주됩니다. 이러한 도메인에서 리소스를 로드 하려면 하위 도메인이 명시 적으로 나열되어야 합니다. 예를 들어 https : //*.cloudfront.net은 유효하지 않지만 https://XXXX.cloudfront.net 및 https : //*.XXXX.cloudfront.net은 허용 목록에 포함될 수 있습니다.


개발의 용이성을 위해 로컬 컴퓨터의 서버에서 HTTP를 통해 로드 된 리소스를 허용 목록에 추가 할 수 있습니다. http://127.0.0.1 또는 http : // localhost의 모든 포트에서 스크립트 및 개체 소스를 허용 할 수 있습니다.


HTTP를 통해 로드 된 리소스에 대한 제한은 직접 실행되는 리소스에만 적용됩니다. 예를 들어 원하는 오리진에 대한 XMLHTTPRequest 연결을 만들 수 있습니다. 기본 정책은 어떤 식으로든 connect-src 또는 다른 CSP 지시문을 제한하지 않습니다.


HTTPS를 통해 example.com에서 스크립트 리소스를 로드 할 수 있는 완화 된 정책 정의는 다음과 같습니다.

"content_security_policy": "script-src 'self' https://example.com; object-src 'self'"

script-src 및 object-src는 모두 정책에 의해 정의됩니다. Chrome은 이러한 각 값을 (적어도) 'self'로 제한하지 않는 정책을 허용하지 않습니다.


Google Analytics를 사용하는 것이 이러한 종류의 정책 정의에 대한 표준 예입니다. Google Analytics 샘플 확장을 사용하여 이벤트 추적에서 일종의 Analytics 상용구를 제공하고 더 자세히 설명하는 간단한 자습서를 제공하는 것이 일반적입니다.


평가 된 JavaScript 


eval () 및 setTimeout (String), setInterval (String) 및 new Function (String)과 같은 관련 정책은 정책에 'unsafe-eval'을 추가하여 완화 할 수 있습니다.

"content_security_policy": "script-src 'self' 'unsafe-eval'; object-src 'self'"

그러나 이렇게 하지 않는 것이 좋습니다. 이러한 기능은 악명 높은 XSS 공격 벡터입니다.


기본 정책 강화 


물론 편의를 희생하면서 보안을 강화하기 위해 확장이 허용하는 범위까지 이 정책을 강화할 수 있습니다. 확장 프로그램이 자체 패키지에서 모든 유형 (이미지 등)의 리소스 만로드 할 수 있도록 지정하려면 default-src 'self'정책이 적합합니다. Mappy 샘플 확장은 기본값 이상으로 잠겨있는 확장의 좋은 예입니다.


콘텐츠 스크립트 


우리가 논의한 정책은 확장 프로그램의 배경 페이지이벤트 페이지에 적용됩니다. 확장의 콘텐츠 스크립트에 적용하는 방법은 더 복잡합니다.


콘텐츠 스크립트는 일반적으로 확장 CSP의 적용을 받지 않습니다. 콘텐츠 스크립트는 HTML이 아니기 때문에 이것이 권장되지는 않지만 확장의 CSP가 unsafe-eval을 지정하지 않더라도 eval을 사용할 수 있다는 것입니다. 또한 페이지의 CSP는 콘텐츠 스크립트에 적용되지 않습니다. 더 복잡한 것은 콘텐츠 스크립트가 생성하고 실행 중인 페이지의 DOM에 넣는 <script> 태그입니다. 앞으로 이를 DOM 삽입 스크립트라고 부를 것입니다.


페이지에 삽입하는 즉시 실행되는 DOM 삽입 스크립트는 예상대로 실행됩니다. 다음 코드가 포함 된 콘텐츠 스크립트를 간단한 예로 상상해보십시오.

   document.write("<script>alert(1);</script>");

이 콘텐츠 스크립트는 document.write() 즉시 경고를 발생 시킵니다. 이는 페이지에서 지정할 수 있는 정책에 관계없이 실행됩니다.


그러나 DOM 주입 스크립트 내부와 주입시 즉시 실행되지 않는 스크립트의 동작은 더 복잡해집니다. 우리의 확장이 script-src 'self'를 지정하는 자체 CSP를 제공하는 페이지에서 실행되고 있다고 상상해보십시오. 이제 콘텐츠 스크립트가 다음 코드를 실행한다고 상상해보십시오.

   document.write("<button onclick='alert(1);'>click me</button>'");

사용자가 해당 버튼을 클릭하면 onclick 스크립트가 실행되지 않습니다. 이는 스크립트가 즉시 실행되지 않았고 클릭 이벤트가 발생할 때까지 해석되지 않은 코드는 콘텐츠 스크립트의 일부로 간주되지 않으므로 페이지의 CSP (확장 프로그램 아님)가 동작을 제한하기 때문입니다. 그리고 해당 CSP는 안전하지 않은 인라인을 지정하지 않기 때문에 인라인 이벤트 처리기가 차단됩니다.


이 경우 원하는 동작을 구현하는 올바른 방법은 다음과 같이 콘텐츠 스크립트의 함수로 onclick 핸들러를 추가하는 것입니다.

    document.write("<button id='mybutton'>click me</button>'");
    var button = document.getElementById('mybutton');
    button.onclick = function() {
      alert(1);
    };

콘텐츠 스크립트가 다음을 실행하는 경우 또 다른 유사한 문제가 발생합니다.

    var script = document.createElement('script');
    script.innerHTML = 'alert(1);'
    document.getElementById('body').appendChild(script);

이 경우 스크립트가 실행되고 경고가 나타납니다. 그러나 다음 경우를 고려하십시오.

    var script = document.createElement('script');
    script.innerHTML = 'eval("alert(1);")';
    document.getElementById('body').appendChild(script);

초기 스크립트가 실행되는 동안 eval 호출이 차단됩니다. 즉, 초기 스크립트 실행은 허용되지만 스크립트 내의 동작은 페이지의 CSP에 의해 규제됩니다.


따라서 확장에 DOM 삽입 스크립트를 작성하는 방법에 따라 페이지의 CSP를 변경하면 확장의 동작에 영향을 미칠 수 있습니다. 콘텐츠 스크립트는 페이지의 CSP의 영향을 받지 않기 때문에 DOM 삽입 스크립트가 아닌 콘텐츠 스크립트에 가능한 한 많은 확장 기능을 적용해야 하는 큰 이유입니다.


https://developer.chrome.com/extensions/contentSecurityPolicy



댓글목록 0

등록된 댓글이 없습니다.

웹학교 로고

온라인 코딩학교

코리아뉴스 2001 - , All right reserved.