콘텐츠 스크립트

콘텐츠 스크립트는 웹페이지 컨텍스트에서 실행되는 파일입니다. 표준 문서 객체 모델 (DOM)을 사용하여 브라우저에서 방문하는 웹페이지의 세부정보를 읽고, 웹페이지를 변경하고, 정보를 상위 확장 프로그램에 전달할 수 있습니다.

콘텐츠 스크립트 기능 이해하기

콘텐츠 스크립트는 메시지를 확장 프로그램과 교환하여 상위 확장 프로그램에서 사용하는 Chrome API에 액세스할 수 있습니다. 또한 chrome.runtime.getURL()로 확장 프로그램 파일의 URL에 액세스하고 결과를 다른 URL과 동일하게 사용할 수 있습니다.

// Code for displaying EXTENSION_DIR/images/myimage.png:
var imgURL = chrome.runtime.getURL("images/myimage.png");
document.getElementById("someImage").src = imgURL;

또한 콘텐츠 스크립트는 다음 Chrome API에 직접 액세스할 수 있습니다.

콘텐츠 스크립트는 다른 API에 직접 액세스할 수 없습니다.

고립된 환경에서의 작업

콘텐츠 스크립트는 고립된 환경에 존재하므로 콘텐츠 스크립트가 페이지 또는 추가 콘텐츠 스크립트와 충돌하지 않고 자바스크립트 환경을 변경할 수 있습니다.

확장 프로그램은 아래 예와 유사한 코드를 사용하여 웹페이지에서 실행할 수 있습니다.

<html>
  <button id="mybutton">click me</button>
  <script>
    var greeting = "hello, ";
    var button = document.getElementById("mybutton");
    button.person_name = "Bob";
    button.addEventListener("click", function() {
      alert(greeting + button.person_name + ".");
    }, false);
  </script>
</html>

이 확장 프로그램은 다음 콘텐츠 스크립트를 삽입할 수 있습니다.

var greeting = "hola, ";
var button = document.getElementById("mybutton");
button.person_name = "Roberto";
button.addEventListener("click", function() {
  alert(greeting + button.person_name + ".");
}, false);

버튼을 누르면 두 알림이 모두 표시됩니다.

격리된 환경에서는 콘텐츠 스크립트, 확장 프로그램, 웹페이지에서 다른 개발자가 만든 변수 또는 함수에 액세스할 수 없습니다. 이렇게 하면 콘텐츠 스크립트에 웹페이지에서 액세스하면 안 되는 기능을 사용 설정할 수 있습니다.

스크립트 삽입

콘텐츠 스크립트는 프로그래매틱 방식 또는 선언적으로 삽입될 수 있습니다.

프로그래매틱 방식으로 삽입

특정 경우에 실행해야 하는 콘텐츠 스크립트에 프로그래매틱 방식의 삽입을 사용합니다.

프로그래매틱 콘텐츠 스크립트를 삽입하려면 매니페스트에서 activeTab 권한을 제공하세요. 이렇게 하면 활성 사이트의 호스트에 대한 보안 액세스 권한과 권한에 대한 임시 액세스 권한이 부여되어 교차 출처 권한을 지정하지 않고도 현재 활성 탭에서 콘텐츠 스크립트를 실행할 수 있습니다.

{
  "name": "My extension",
  ...
  "permissions": [
    "activeTab"
  ],
  ...
}

콘텐츠 스크립트는 코드로 삽입될 수 있습니다.

chrome.runtime.onMessage.addListener(
  function(message, callback) {
    if (message == "changeColor"){
      chrome.tabs.executeScript({
        code: 'document.body.style.backgroundColor="orange"'
      });
    }
  });

또는 전체 파일을 삽입할 수도 있습니다.

chrome.runtime.onMessage.addListener(
  function(message, callback) {
    if (message == "runContentScript"){
      chrome.tabs.executeScript({
        file: 'contentScript.js'
      });
    }
  });

선언적으로 삽입

지정된 페이지에서 자동으로 실행되어야 하는 콘텐츠 스크립트에 선언적 삽입을 사용합니다.

선언적으로 삽입된 스크립트는 매니페스트의 "content_scripts" 필드에 등록됩니다. 자바스크립트 파일, CSS 파일 또는 둘 다를 포함할 수 있습니다. 모든 자동 실행 콘텐츠 스크립트는 일치 패턴을 지정해야 합니다.

{
 "name": "My extension",
 ...
 "content_scripts": [
   {
     "matches": ["http://*.nytimes.com/*"],
     "css": ["myStyles.css"],
     "js": ["contentScript.js"]
   }
 ],
 ...
}
이름 유형 설명
matches {: #일치 } 문자열 배열 필수사항. 이 콘텐츠 스크립트가 삽입될 페이지를 지정합니다. 이러한 문자열의 구문에 대한 자세한 내용은 일치 패턴을 참조하고 URL을 제외하는 방법은 일치 패턴 및 globs를 참조하세요.
css {: #css } 문자열 배열 선택사항. 일치하는 페이지에 삽입할 CSS 파일의 목록입니다. 이는 페이지에 DOM이 구성되거나 표시되기 전에 이 배열에 표시된 순서대로 삽입됩니다.
js {: #js } 문자열 배열 선택사항. 일치하는 페이지에 삽입할 자바스크립트 파일의 목록입니다. 이 배열에 표시된 순서대로 삽입됩니다.
match_about_blank {: #match_about_blank } boolean 선택사항. 상위 프레임 또는 오프너 프레임이 matches에 선언된 패턴 중 하나와 일치하는 about:blank 프레임에 스크립트를 삽입해야 하는지 여부입니다. 기본값은 false입니다.

일치 및 glob 제외

지정된 페이지 일치는 매니페스트 등록에 다음 필드를 포함하여 맞춤설정할 수 있습니다.

이름 유형 설명
exclude_matches {: #embed_matches } 문자열 배열 선택사항. 이 콘텐츠 스크립트가 삽입될 페이지는 제외됩니다. 이러한 문자열의 구문에 대한 자세한 내용은 일치 패턴을 참고하세요.
include_globs {: #include_globs } 문자열 배열 선택사항. 이 glob도 일치하는 URL만 포함하도록 matches 다음에 적용됩니다. @include Greasemonkey 키워드를 에뮬레이션하기 위한 것입니다.
exclude_globs {: #embed_globs } 문자열 배열 선택사항. 이 glob과 일치하는 URL을 제외하도록 matches 다음에 적용됩니다. @excludeGreasemonkey 키워드를 에뮬레이션하기 위한 것입니다.

URL이 exclude_matches 또는 exclude_globs 패턴과 일치하지 않는 한 콘텐츠 스크립트는 URL이 matches 패턴 및 include_globs 패턴과 일치하면 페이지에 삽입됩니다.

matches 속성이 필요하므로 exclude_matches, include_globs, exclude_globs는 영향을 받는 페이지를 제한하는 데만 사용할 수 있습니다.

다음 확장 프로그램은 콘텐츠 스크립트를 http://www.nytimes.com/ health에 삽입하지만 http://www.nytimes.com/ business에는 삽입하지 않습니다 .

{
  "name": "My extension",
  ...
  "content_scripts": [
    {
      "matches": ["http://*.nytimes.com/*"],
      "exclude_matches": ["*://*/*business*"],
      "js": ["contentScript.js"]
    }
  ],
  ...
}

Glob 속성은 일치 패턴보다 더 유연한 구문을 따릅니다. 허용되는 glob 문자열은 '와일드 카드' 별표와 물음표를 포함할 수 있는 URL입니다. 별표 *는 빈 문자열을 포함하여 모든 길이의 문자열과 일치하고 물음표 ?는 모든 단일 문자와 일치합니다.

예를 들어 glob http:// ??? .example.com/foo/ *는 다음과 일치합니다.

  • http:// www .example.com/foo /bar
  • http:// .example.com/foo /

하지만 다음과 일치하지 않습니다.

  • http:// my .example.com/foo/bar
  • http:// example .com/foo/
  • http://www.example.com/foo

이 확장 프로그램은 콘텐츠 스크립트를 http:/www.nytimes.com/ arts /index.htmlhttp://www.nytimes.com/ jobs /index.html에 삽입하지만 http://www.nytimes.com/ sports /index.html에는 삽입하지 않습니다.

{
  "name": "My extension",
  ...
  "content_scripts": [
    {
      "matches": ["http://*.nytimes.com/*"],
      "include_globs": ["*nytimes.com/???s/*"],
      "js": ["contentScript.js"]
    }
  ],
  ...
}

이 확장 프로그램은 콘텐츠 스크립트를 http:// history .nytimes.comhttp://.nytimes.com/ history에 삽입하지만 http:// Science .nytimes.com 또는 http://www.nytimes.com/ Science에는 삽입하지 않습니다 .

{
  "name": "My extension",
  ...
  "content_scripts": [
    {
      "matches": ["http://*.nytimes.com/*"],
      "exclude_globs": ["*science*"],
      "js": ["contentScript.js"]
    }
  ],
  ...
}

올바른 범위를 달성하기 위해 이 중 하나, 전부 또는 일부를 포함할 수 있습니다.

{
  "name": "My extension",
  ...
  "content_scripts": [
    {
      "matches": ["http://*.nytimes.com/*"],
      "exclude_matches": ["*://*/*business*"],
      "include_globs": ["*nytimes.com/???s/*"],
      "exclude_globs": ["*science*"],
      "js": ["contentScript.js"]
    }
  ],
  ...
}

운영 기간

자바스크립트 파일이 웹페이지에 삽입되면 run_at 필드로 제어됩니다. 환경설정된 기본 필드는 "document_idle"이지만 필요한 경우 "document_start" 또는 "document_end"로 지정할 수도 있습니다.

{
  "name": "My extension",
  ...
  "content_scripts": [
    {
      "matches": ["http://*.nytimes.com/*"],
      "run_at": "document_idle",
      "js": ["contentScript.js"]
    }
  ],
  ...
}
이름 유형 설명
document_idle {: #document_idle } string 권장. 가능하면 "document_idle"를 사용합니다.

브라우저는 "document_end"windowonload 이벤트 실행 직후에 스크립트를 삽입할 시간을 선택합니다. 삽입 시점의 정확한 시점은 문서의 복잡도와 로드에 걸리는 시간에 따라 달라지며 페이지 로드 속도에 최적화되어 있습니다.

"document_idle"에서 실행되는 콘텐츠 스크립트는 window.onload 이벤트를 수신 대기할 필요가 없으며 DOM이 완료된 후 실행됩니다. 스크립트를 window.onload 이후에 실행해야 하는 경우 확장 프로그램에서 document.readyState 속성을 사용하여 onload가 이미 실행되었는지 확인할 수 있습니다.
document_start {: #document_start } string 스크립트는 css의 모든 파일 뒤에 삽입되지만, 다른 DOM이 구성되거나 다른 스크립트가 실행되기 전에 삽입됩니다.
document_end {: #document_end } string 스크립트는 DOM이 완료된 직후, 그러나 이미지 및 프레임과 같은 하위 리소스가 로드되기 전에 삽입됩니다.

프레임 지정

"all_frames" 필드를 사용하면 확장 프로그램에서 자바스크립트 및 CSS 파일을 지정된 URL 요구사항과 일치하는 모든 프레임에 삽입해야 하는지, 아니면 탭의 최상위 프레임에만 삽입해야 하는지 지정할 수 있습니다.

{
  "name": "My extension",
  ...
  "content_scripts": [
    {
      "matches": ["http://*.nytimes.com/*"],
      "all_frames": true,
      "js": ["contentScript.js"]
    }
  ],
  ...
}
이름 유형 설명
all_frames {: #all_frames } boolean 선택사항. 기본값은 false이며, 이는 상단 프레임만 일치한다는 의미입니다.

true을 지정하면 프레임이 탭의 최상위 프레임이 아니더라도 모든 프레임에 삽입됩니다. 각 프레임은 URL 요구사항을 개별적으로 확인하며 URL 요구사항이 충족되지 않으면 하위 프레임에 삽입되지 않습니다.

삽입 페이지와의 커뮤니케이션

콘텐츠 스크립트의 실행 환경과 이를 호스팅하는 페이지는 서로 격리되어 있지만 페이지의 DOM에 대한 액세스 권한은 공유합니다. 페이지가 콘텐츠 스크립트와 통신하거나 콘텐츠 스크립트를 통해 확장 프로그램과 통신하려는 경우 공유 DOM을 통해 통신해야 합니다.

window.postMessage를 사용하여 다음과 같은 작업을 실행할 수 있습니다.

var port = chrome.runtime.connect();

window.addEventListener("message", function(event) {
  // We only accept messages from ourselves
  if (event.source != window)
    return;

  if (event.data.type && (event.data.type == "FROM_PAGE")) {
    console.log("Content script received: " + event.data.text);
    port.postMessage(event.data.text);
  }
}, false);
document.getElementById("theButton").addEventListener("click",
    function() {
  window.postMessage({ type: "FROM_PAGE", text: "Hello from the webpage!" }, "*");
}, false);

비확장 페이지(example.html)는 자체 페이지에 메시지를 게시합니다. 이 메시지는 콘텐츠 스크립트에서 가로채서 검사한 후 확장 프로그램 프로세스에 게시됩니다. 이러한 방식으로 페이지에서 확장 프로그램 프로세스와 통신할 수 있는 라인이 설정됩니다. 반대의 경우도 비슷한 방법을 통해 가능합니다.

보안 유지

격리된 환경은 보호 레이어를 제공하지만 콘텐츠 스크립트를 사용하면 확장 프로그램 및 웹페이지에 취약점이 발생할 수 있습니다. 콘텐츠 스크립트가 별도의 웹사이트에서 콘텐츠를 수신(예: XMLHttpRequest 생성)하는 경우 삽입하기 전에 콘텐츠 크로스 사이트 스크립팅 공격을 필터링해야 합니다. "man-in-the-middle" 공격을 방지하려면 HTTPS를 통해서만 통신하세요.

악성 웹페이지를 필터링하세요. 예를 들어 다음 패턴은 위험합니다.

var data = document.getElementById("json-data")
// WARNING! Might be evaluating an evil script!
var parsed = eval("(" + data + ")")
var elmt_id = ...
// WARNING! elmt_id might be "); ... evil script ... //"!
window.setTimeout("animate(" + elmt_id + ")", 200);

대신 스크립트를 실행하지 않는 더 안전한 API를 사용하세요.

var data = document.getElementById("json-data")
// JSON.parse does not evaluate the attacker's scripts.
var parsed = JSON.parse(data);
var elmt_id = ...
// The closure form of setTimeout does not evaluate scripts.
window.setTimeout(function() {
  animate(elmt_id);
}, 200);