

WEBサイト内にiframeを表示するChrome拡張を開発しているのですが、  
Twitterのページでcontent_security_policyに関するエラーが出てiframeを表示出来なくて困っています。  
（Twitter以外のページではiframeを表示出来ています。）

manufest.jsonのcontent_security_policyを適宜設定すれば良いと思うのですが、  
リファレンスを見て色々試してみたのですが、全く上手くいきません。  
どなたか解決までいかずとも、御指南、アドバイスを頂けないでしょうか。  
宜しくお願いいたします。

●Chromeのコンソールに出力されるエラー内容

[code]

    Refused to frame 'https://domain.com/' because it violates the following Content Security Policy directive: "frame-src 'self' https://twitter.com https://*.twimg.com https://player.vimeo.com https://pay.twitter.com https://ton.twitter.com https://syndication.twitter.com https://vine.co twitter: https://www.youtube.com https://platform.twitter.com https://upload.twitter.com".
    
    Failed to execute 'postMessage' on 'DOMWindow': The target origin provided ('https://localhost:8080') does not match the recipient window's origin ('null').
    
[/code]

●manufest.json

[code]

    {
        "manifest_version": 2,
        "content_security_policy": "default-src 'self' https://sample.com/; child-src 'self' https://sample.com/; object-src 'self' https://sample.com/; frame-src 'self' https://sample.com/ https://twitter.com https://*.twimg.com https://player.vimeo.com https://pay.twitter.com https://ton.twitter.com https://syndication.twitter.com https://vine.co twitter: https://www.youtube.com https://platform.twitter.com https://upload.twitter.com;",
        "name": "sample",
        "description": "sample",
        "content_scripts": [
          {
            "matches": [***],
            "js": [ "contentScript.js" ],
            "run_at": "document_end"
          }
        ],
        "permissions": [
          "storage"
        ],
        "version": "0.672"
    }
    
[/code]


CC BY-SA 4.0
2018-12-18T12:13:43.603
51334
2020-01-28T01:01:40.330
31511
question
chrome-extension
Chrome拡張のcontent_security_policyの設定について


そのエラーはmanifest.jsonの`content_security_policy`にはあまり関係ありません。それは拡張機能のコンテキストで実行されるスクリプトのセキュリティを指定するものです。  
一方、今回のエラーはTwitterが設定しているCSPによって引き起こされています。  
contentScriptは各Webサイト上（Twitterを表示している場合はTwitterのWebサイト上）で動作するため、そのサイトが設定するCSPの影響を受けるのです。

* * *

ここでは、[英語版Stack
Overflowにおける同様の質問](https://stackoverflow.com/questions/24641592/injecting-
iframe-into-page-with-restrictive-content-security-
policy)で回答されている、[web_accesible_resources](https://developer.chrome.com/extensions/manifest/web_accessible_resources)を用いてCSPを迂回する手法を紹介します。

`web_accessible_resources`はその名の通り、拡張機能からウェブページ内に提供されるリソースを宣言するものです。ここで宣言されているリソースは（ウェブページが設定しているCSPに制限されずに）contentScriptから利用することができます。  
そこで、`frame.html`というページを拡張機能内に用意して、それをcontentScriptから読み込むようにします。このcontentScriptはTwitterのウェブページ上ではなく拡張機能内に存在するページですから、Twitterが設定したCSPの影響を受けずにさらに他のページを埋め込むことができるのです。

具体的な方法は、まず`manifest.json`の`web_accessible_resources`を宣言して`frame.html`を追加します。

[code]

    {
        "manifest_version": 2,
        "name": "sample",
        "description": "sample",
        "content_scripts": [
          { 
            "matches": ["*://*/*"],
            "js": [ "contentScript.js" ],
            "run_at": "document_end"
          }
        ],
        "permissions": [
          "storage"
        ],
        "web_accessible_resources": [
          "frame.html"
        ],
        "version": "0.672"
    }
    
[/code]

`contentScript.js`の中からは[chrome.runtime.getURL](https://developer.chrome.com/extensions/runtime#method-
getURL)を使用して`frame.html`のURLを得ることができます。

[code]

    // 適当な位置にiframeを生成
    const iframe = document.createElement('iframe');
    // 外部サイトを直接埋め込む代わりに拡張機能に同梱したframe.htmlを埋め込む
    const frameURL = chrome.runtime.getURL('frame.html');
    iframe.src = frameURL;
    
    // 適当に目立たせる
    Object.assign(iframe.style, {
        position: 'absolute',
        left: '100px',
        top: '100px',
        width: '500px',
        height: '500px',
        border: '5px solid black',
    });
    
    document.body.appendChild(iframe);
    
[/code]

そして、`frame.html`の中でさらにiframeを用いて目的のサイトを埋め込みます。

[code]

    <!doctype html>
    <html>
      <head>
        <title></title>
        <style>
          html, body {
            margin: 0;
            width: 100%;
            height: 100%;
            font-size: 0;
          }
          iframe {
            width: 100%;
            height: 100%;
            border: none;
          }
        </style>
      </head>
      <body>
        <!-- 目的のサイトを全画面で埋め込む -->
        <iframe src="https://example.com/"></iframe>
      </body>
    </html>
    
[/code]

以上の方法で、TwitterのようにCSPが設定されたサイトでも外部のサイトを埋め込むことができました。  
なお、今回埋め込む外部サイトは`frame.html`内にベタ書きですが、動的に指定する必要がある場合は適当に`postMessage`などで通信すれば可能です。


CC BY-SA 4.0
2018-12-19T15:46:25.210
51360
2018-12-19T15:57:13.920
2018-12-19T15:57:13.920
30079
30079
51334
answer