Facebookにリンクを書き換えさせないChrome拡張機能を作る

要約

Facebookの外部リンクをクリックすると、l.​facebook​.​comドメインのリンクが開き、その後本来のリンク先へリダイレクトされるという、スパムにも似た挙動を示すことが指摘されている。
将来の自衛と学習を兼ね、表示通りのアドレスのリンクを直接開くChrome拡張機能を作成し、機能することを確認した。
今回は要素(DOM)の変更を監視するために、JavaScript APIの MutationObserver を利用した。

Facebookの不思議な挙動

Facebookのページで外部リンクをクリックすると、ページ上の表示およびリンクプレビューは正しいアドレスを示しているにもかかわらず、l.​facebook​.​comドメインのリンクが開き、その後本来のリンク先へリダイレクトされることが指摘されています(話題の元となったツイートを以下に示します)。

技術的には、onmousedownイベントおよびonmouseoverイベントでaタグのhref属性(リンク)を書き換えており、クリックした瞬間だけリンクが書き換わっている状態を作り出しているようです。
したがって、右クリックメニューの「新しいタブで開く」などで開くリンクも同様に書き換わったものとなります。

ユーザから見えるアドレスと異なるリンクが開くという、まるでフィッシングの手口のような挙動ですが、何とか対策はできないものでしょうか。

ということで、「Facebook上で表示通りのアドレスのリンクを開く」ためのGoogle Chromeの拡張機能を作成してみます。

要素(DOM)変更の監視

アドレス書き換えがonmousedownイベントで実行されることが分かっていても、その実行自体を止めることは困難と考えました。

そこで本記事では、アドレスが書き換わったことを検知する方法として、JavaScriptの機能である MutationObserver を利用します。

MutationObserver インターフェイスは、 DOM ツリーへ変更が加えられたことを監視することができる機能を提供します。

これにより、aタグのhref要素がl.​facebook​.​comに変更されたら元の値に戻すことを試みます。
ソースコードは次項のcontent.jsで示します。

Chrome拡張機能の作成

注意:
以下に示す拡張機能は簡単な動作確認のみを行っており、動作を保証するものではありません。

本拡張機能の導入・実行は自己責任でお願いします。

以下のファイルを同じディレクトリに配置し、Google Chromeの「パッケージ化されていない拡張機能を読み込む」にて同ディレクトリを読み込むことで拡張機能として動作します。

{
    "name": "Facebook Link Defender",
    "version": "1.0.0",
    "manifest_version": 2,
    "description": "Prevents to change link on click, at Facebook.",
    "content_scripts": [{
        "matches": ["https://www.facebook.com/*"],
        "js": [
            "content.js"
        ]
    }]
}
// body 全体を監視する
var target = document.body;

// オブザーバーのインスタンスを生成
var observer = new MutationObserver((mutations) => {
    mutations.forEach((mutation) => {
        const {type, target, oldValue} = mutation;
        if (type === 'attributes') {
            // 書き換わった後の URL が特定の文字列で始まっていたら、前の値に戻す
            if (target.href.startsWith(`https://l.facebook.com/`)) {
                target.href = oldValue;
            }
        }
    });
});

// オブザーバーのオプション
// 子孫ノード全ての href 属性を監視
var config = {
    attributes: true,
    attributeOldValue: true,
    attributeFilter: ['href'],
    childList: true,
    characterData: false,
    subtree: true
};

// 対象ノードの設定された変更の監視を開始
observer.observe(target, config);

拡張機能の作り方については以下記事を参考にしました。

実行結果 – 成功

拡張機能を有効にしてFacebook内の外部リンクを左クリックで開くと、l.​facebook​.​comを経由せずにオリジナルのページを開くことができました。
また、右クリックでリンクのアドレスをコピーした場合にもオリジナルのアドレスを取得できました。

まとめ

本記事ではMutationObserverで要素の変更を監視し、それに対応する処理を実行する拡張機能を作成しました。
フレームワークの充実した現在ではWeb開発においてDOMを直接操作する機会は減っていますが、今回のようなケースでは単純かつ効果的な手段として利用できました。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

CAPTCHA