Cookie プラグインと画像アップロードでXSS攻撃になりかけた話と、最終的に選んだ安全な対策
By xxx / 2月 5, 2026 / コメントはまだありません / ブログ
Cookie プラグインと画像アップロードで「XSS攻撃になりかけた」話と、最終的に選んだ安全な実装方法
Web サイトを運営していると、思わぬところにセキュリティの落とし穴が潜んでいます。
今回は、私自身が実際に体験した 「Cookie プラグイン」と「貼り付けた画像」 による XSS(クロスサイトスクリプティング)リスクについてまとめます。
最終的には、functions.php だけで安全に Cookie 同意バナーを実装し、GTM を同意後のみ発火させる方法に落ち着きました。
同じように悩んでいる方の参考になれば幸いです。
—
1. Cookie プラグインで起きた問題
最初は、一般的な Cookie 同意プラグインを使っていました。
しかし、ある日ふと気づいたのが、
• プラグインが読み込む外部スクリプト
• プラグインが生成する HTML
• プラグインが扱う Cookie の値
これらが XSS の入口になり得るという点でした。
特に、ユーザーが入力した値をそのまま HTML に差し込むタイプのプラグインは、
設定次第で簡単に XSS の温床になります。
「便利だから」と安易に導入したプラグインが、
実はセキュリティリスクを増やしていたわけです。
—
2. 貼り付けた画像が XSS になりかけた話
もうひとつの問題は「画像アップロード」です。
通常、画像ファイル(JPEG/PNG)は JavaScript を実行できません。
しかし、SVG だけは別です。
SVG は XML 形式なので、
中に <script> を埋め込むことができ、
悪意ある SVG をアップロードすると XSS が成立します。
私が遭遇したのは、
「画像として貼り付けたファイルが実は SVG で、
ブラウザがその中のスクリプトを解釈しようとした」というケースでした。
WordPress はデフォルトで SVG を禁止していますが、
テーマやプラグインによっては許可されてしまうことがあります。
—
3. プラグインをやめて、functions.php だけで実装することにした
Cookie プラグインのリスクと、画像アップロードの XSS 問題を経験した結果、
私は プラグインを使わず、自分で安全な Cookie 同意バナーを実装するという選択をしました。
目的はシンプルです。
• 同意しないユーザーは追跡しない
• 同意したユーザーだけ GTM を読み込む
• サイト閲覧自体はブロックしない(UX・SEO の観点)
• 外部プラグインに依存しない
• XSS の入口を増やさない
この方針に沿って、functions.php に必要最低限のコードだけを追加しました。
—
4. 実際に使っている安全な Cookie 同意バナー(functions.php のみ)
以下は、私が現在使っている 画面右下に固定表示される Cookie 同意ボタンです。
同意後にだけ GTM が読み込まれます。
add_action('wp_footer', function() {
?>
<style>
#consent-btn {
position: fixed;
bottom: 20px;
right: 20px;
padding: 12px 20px;
background: #0073aa;
color: #fff;
border: none;
border-radius: 6px;
font-size: 16px;
cursor: pointer;
z-index: 99999;
}
</style>
<?php if (!isset($_COOKIE['cookie_consent'])) : ?>
<button id="consent-btn">同意してサイトを利用する</button>
<?php endif; ?>
<script>
document.addEventListener('DOMContentLoaded', function() {
var btn = document.getElementById('consent-btn');
if (btn) {
btn.addEventListener('click', function() {
localStorage.setItem('cookie_consent', 'true');
document.cookie = "cookie_consent=true; path=/;";
location.reload();
});
}
if (localStorage.getItem('cookie_consent') === 'true') {
var gtm = document.createElement('script');
gtm.async = true;
gtm.src = "https://www.googletagmanager.com/gtm.js?id=GTM-XXXXXXX";
document.head.appendChild(gtm);
}
});
</script>
<?php
});
この実装のポイント
- プラグイン不要
- 外部入力を HTML に挿入しないため XSS に強い
- 同意しない限り GTM は動かない
- サイト閲覧はブロックしない(一般的な仕様)
- テーマ構造に依存しない
- なぜ「同意しなくてもサイトを読める」方式にしたのか
Cookie 同意バナーには大きく2種類あります。
種類 動作 メリット
一般的な方式 同意しなくてもサイトは読める UXが良い、SEOに影響しない、法律的に正しい
ブロッカー型 同意するまでサイトを読めない 法的に強いが、離脱率が高い
私は 一般的な方式 を採用しました。
理由は:
- GDPR でも「サイト閲覧自体は同意不要」
- Google はブロッカー型を嫌う(SEOに悪影響)
- ユーザー体験が悪くなる
- 私のサイトは広告目的ではない
つまり、最もバランスが良い方式です。
- XSS を防ぐために気をつけていること
今回の経験から、私は次の点を徹底するようになりました。
- 不要な Cookie プラグインは使わない
- SVG をアップロードしない
- 外部入力を innerHTML に入れない
- テーマやプラグインのアップローダーを信用しすぎない
- functions.php で必要最低限のコードだけを書く
特に SVG は本当に危険で、
「画像だから安全」と思っていると痛い目に遭います。
- まとめ
今回の経験で学んだのは、
- 便利なプラグインほど XSS の入口になりやすい
- 画像アップロードも安全とは限らない(特に SVG)
- Cookie 同意は自作したほうが安全で軽い
- 同意しないユーザーは追跡しないのが正しい
- functions.php だけで十分実装できる
ということでした。
同じように悩んでいる方の参考になれば嬉しいです。
参考
子テーマ、style.css、functions.php
サーバー
↓
コントロールパネル
↓
サイト名
↓
ftpファイルマネージャー
↓
wp-content
↓
themes
↓
新規ディレクトリ(新規フォルダ)子テーマ作成
yourtheme-child
↓
新規ファイル(2つ作成)
style.css
functions.php
↓※親テーマにはクラシックかブロックがあるが、子テーマにfooter.phpを作らなくても仕上がる
style.css
/*
Theme Name: 子テーマ(例:aaaaa-child)
Template: 親テーマ(例:aaaaa)
*/※WordPressのテーマ、テーマのバージョンアップに連動する書き換え用(子)テーマとして-childを追加
functions.php
<?php
// 親テーマのCSSを読み込む
add_action( 'wp_enqueue_scripts', function() {
wp_enqueue_style( 'parent-style', get_template_directory_uri() . '/style.css' );
});
// Cookie 同意ボタンと GTM の制御
add_action('wp_footer', function() {
?>
<style>
#consent-btn {
position: fixed;
bottom: 20px;
right: 20px;
padding: 12px 20px;
background: #0073aa;
color: #fff;
border: none;
border-radius: 6px;
font-size: 16px;
cursor: pointer;
z-index: 99999;
}
</style>
<?php if (!isset($_COOKIE['cookie_consent'])) : ?>
<button id="consent-btn">同意してサイトを利用する</button>
<?php endif; ?>
<script>
document.addEventListener('DOMContentLoaded', function() {
var btn = document.getElementById('consent-btn');
if (btn) {
btn.addEventListener('click', function() {
localStorage.setItem('cookie_consent', 'true');
document.cookie = "cookie_consent=true; path=/;";
location.reload();
});
}
if (localStorage.getItem('cookie_consent') === 'true') {
var gtm = document.createElement('script');
gtm.async = true;
gtm.src = "https://www.googletagmanager.com/gtm.js?id=GTM-XXXXXXX";
document.head.appendChild(gtm);
}
});
</script>
<?php
});※https://www.googletagmanager.comを検索、GTM-XXXXXXXはコンテナIDのGTM-XXXXXXXのこと