Chrome拡張機能でリクエストヘッダrefererの書き換え

Chrome拡張機能で content script や background スクリプト内でのajaxリクエスト時にリクエストヘッダ(今回はリファラreferer)を書き換える方法をメモしておきます。

目次

前提

  • Chrome 75.0.3770.100(Official Build) (64 ビット)

manifest.jsonの設定

manifest.json

{
  "permissions": [
    "<all_urls>",
    "webRequest",
    "webRequestBlocking",
    ...
  ],
  ...
  "background": {
    "scripts": [
      "jquery.js",
      "background.js",
      ...
    ],
    "persistent": true
  },
  ...
}

manifest設定箇所:

  • permissions
    • ヘッダ書き換え処理を発動させたいURLを追加。上記例では<all_urls>を指定して全てのURLをインターセプト。
    • "webRequest"を追加。
    • "webRequestBlocking"を追加。
  • background
    • "persistent": trueを指定。

background.scripts"jquery.js"をロードしています。これは後ほどbackground.js内で$.ajax()するためです。webRequestの設定自体には関係ありません。

サンプルコード

以下コードを実行すると、ajaxリクエストが投げられる直前のタイミングでリクエストヘッダ referer の値が"http://example.com/"に書き換えられます。

background.js

chrome.webRequest.onBeforeSendHeaders.addListener(function(details) {
  // 2) $.ajax()が実行され、リクエストが投げられる直前にここに来る。ここでリクエストヘッダを書き換え可能。

  // refererを "http://example.com/" に書き換え:
  putReqHeader(details, "referer", "http://example.com/");

  return {
    requestHeaders: details.requestHeaders,
  };
}, {
  urls: ["<all_urls>"], // 全URLをインターセプト
}, [
  "requestHeaders",
  "extraHeaders",
  "blocking"
]);

// 1) ローカルのWebサーバにajaxリクエストを実行してみる:
$.ajax({ url: "http://127.0.0.1:3000/" }).done((msg) => {
  console.log("ajax done!");
});

/** details.requestHeaders内のリクエストヘッダを更新する関数 */
function putReqHeader(details, key, val) {
  key = key.toLowerCase();
  for (let n in details.requestHeaders) {
    const got = details.requestHeaders[n].name.toLowerCase() == key;
    if (got) {
      details.requestHeaders[n].value = val;
      return;
    }
  }
  details.requestHeaders.push({
    name: key,
    value: val,
  });
}

コードレビュー

background.js内でchrome.webRequest.onBeforeSendHeaders.addListener() を記述することで、リクエストヘッダが送信される直前のリクエストヘッダを弄ることができます。

chrome.webRequest.onBeforeSendHeaders.addListener()の説明:

  • 第一引数にはdetails.requestHeadersの書き換え処理
  • 第二引数にはurlsにインターセプトしたいURLを指定
  • 第三引数には["requestHeaders", "extraHeaders", "blocking"]を指定 (※)

"extraHeaders"の明示的指定
Chrome 72 からは、以下のリクエストヘッダを書き換えるためには"extraHeaders"を明示的に指定しなければなりません:

  • Accept-Language
  • Accept-Encoding
  • Referer
  • Cookie

参考: chrome.webRequest - chrome

NOTE: 上記例では background.js 内でajaxリクエストを行っていますが、content script内からのajaxリクエストでも同様にリクエストヘッダが書き換わります。

テスト

リクエストヘッダを表示するだけの簡易Webサーバを作り、先ほどのChrome拡張機能がリクエストヘッダを書き換えられているか確かめてみましょう。簡易WebサーバはNode.jsでサクッと書いてみます。

server.js (簡易Webサーバ)

const http = require('http');

const hostname = '127.0.0.1';
const port = 3000;

const server = http.createServer((req, res) => {
  console.log("req.headers:", req.headers); // ここでリクエストヘッダをデバッグ出力
  res.statusCode = 200;
  res.setHeader('Content-Type', 'text/plain');
  res.end('Hello World\n');
});

server.listen(port, hostname, () => {
  console.log(`Server running at http://${hostname}:${port}/`);
});

簡易Webサーバを起動し、先ほどのChrome拡張機能を実行してみます:

$ node server.js 
Server running at http://127.0.0.1:3000/

req.headers: { host: '127.0.0.1:3000',
  ...
  referer: 'http://example.com/' }

ご覧の通り、クライアントからのリクエストヘッダのリファラrefererhttp://example.com/がセットされていることが分かりますね。

以上です。

PR:時事ネタチェックの時間節約!
芽萌丸プログラミング部 @programming
プログラミング関連アカウント。Web標準技術を中心に書いていきます。フロントエンドからサーバサイドまで JavaScript だけで済ませたい人たちの集いです。