メニュー 閉じる

WebExtensionsでRefererヘッダを書き換える

概要

私が公開しているFirefox向けアドオンDownload All Sourcesでは、ダウンロード時のリファラを書き換える機能を実装しています。
リファラとは、HTTPにおけるリクエストヘッダにあるRefererヘッダのことを指します。

XMLHttpRequestやjQuery.ajaxなどを利用する場合、HTTPリクエストヘッダを書き換えることができるのですが、Refererヘッダなど一部のヘッダは、禁止ヘッダと言ってJavaScriptから書き換えることができません。

書き換えられないと言ってもこれは通常のWebページでの話。
アドオンであるWebExtensionsでは書き換える方法が残されているのです。

HTTPリクエストヘッダの書き換え方

まず通常のリクエストヘッダの書き換え方を簡単に。

// XMLHttpRequestの場合
const xhr = new XMLHttpRequest();
xhr.open('GET', 'https://www.google.com/', false);
xhr.setRequestHeader('User-Agent', 'Googlebot/2.1 (+http://www.google.com/bot.html)');
xhr.send();

// jQuery.ajaxの場合
$.ajax({
  url: 'https://www.google.com/',
  type: 'GET',
  headers: {
    'User-Agent': 'Googlebot/2.1 (+http://www.google.com/bot.html)'
  }
})

上記の場合は、User-AgentヘッダをGooglebotを装うように書き換えています。
このやり方でRefererヘッダを書き換えようとした場合、以下の様なエラーによりリクエストが失敗します。

禁止されたヘッダーを設定しようとして拒否されました: Referer

禁止ヘッダの書き換え方

禁止ヘッダの書き換えについては、直接XHRで書き換えることができません。

しかしWebExtensionsのAPIにはbrowser.webRequestというAPIが存在します。

これはブラウザが行うWebリクエストのいろいろなタイミングで、イベントを受け取ることができるようになるAPIです。
このうちonBeforeSendHeadersを使えば、Webリクエストのヘッダ送信直前でイベントを受け取り、書き換えることができるようになります。

Download All Sourcesでどのようにしているかを紹介します。

まずXHRを実行する部分では、書き換えたいリクエストヘッダのヘッダ名に’X-DAS-‘を付与しヘッダを追加します。
例えば、RefererヘッダをそのままXHRのヘッダに追加するとエラーとなるので、X-DAS-Refererとして追加します。

そしてbackgroundページでは、以下の様にイベントリスナーを登録します。

browser.webRequest.onBeforeSendHeaders.addListener(function(details) {
    // origin_url => XHRを発生させるURL
    if (details.originUrl != origin_url) return null;

    // 置き換えるリクエストヘッダ
    const blockingResponse = { requestHeaders : [] };

    for (let header of details.requestHeaders) {
        // ヘッダ名から'X-DAS-'を外して、リクエストヘッダに追加
        if (/^X-DAS-/.test(header.name))
            blockingResponse.requestHeaders.push({
                name : header.name.replace(/^X-DAS-/, ''),
                value : header.value
            });
        // それ以外のヘッダはそのままリクエストヘッダに追加
        else
            blockingResponse.requestHeaders.push(header);
    }
    return blockingResponse;
}, { urls : ["<all_urls>"] }, ["blocking", "requestHeaders"]);

このAPIでは、全てのWebリクエストがインジェクション対象となってしまいます。
そのため、何とかして自身のアドオンが起因となったXHRだけを対象として絞り込む必要があるのですが、20行目のaddListenerの第2引数で指定できるフィルタでは十分にフィルタすることができません。
ちなみに何でフィルタをできるかというと、urls, types, tabId, windowIdの4つで、いずれもアドオンを特定するには力不足。
仕方ないので、3行目のようにXHRが発生したURLを見て識別しています。

また同じく20行目のaddListener第3引数では、"blocking""requestHeaders"を指定しています。
"blocking"を付けることでリクエストの書き換えが可能となり、"requestHeaders"を付けることでdetailsにリクエストヘッダを含めるようになります。

あとは、XHR実行時に付与した’X-DAS-Referer’などのヘッダを、’Referer’のように書き戻してリクエストヘッダに設定します。
これにより無事Refererヘッダを書き換えられました。

コメントを残す