WordPressでブログを運営していると、予期せぬエラーに遭遇することがある。
10記事ほど投稿を終え、まだ読者もほとんどいない立ち上げ初期のブログだが、せっかくなら収益化の設定も体験してみたいと思った。
そこで、Google AdSenseの自動広告コードをサイトに導入してみることにした。
テーマの設定画面にコードを貼り付けて保存ボタンを押した瞬間、画面に見慣れないエラーが表示されて保存が弾かれてしまった。
自分が使っているWordPressテーマ「SANGO」の設定画面で、指定された <script> タグを貼り付けて保存しようとした。
すると「更新に失敗しました」というメッセージとともに、処理が遮断されてしまったのだ。
最初はテーマの不具合か自分のコードの貼り付けミスを疑い、少しばかり焦った。
だが、調査してみると原因はテーマでも入力ミスでもなかった。
レンタルサーバーに標準装備されているセキュリティ機能「WAF」が作動していたのだ。
WAF(Web Application Firewall)は、サイトに対する不正な通信やサイバー攻撃を検知して遮断する盾のような仕組みだ。
一般的なファイアウォールが怪しいIPアドレスなど「ネットワークの入り口」を守るのに対し、WAFはフォームの入力内容など「通信の中身」を監視している。
なぜ通信の中身まで監視する必要があるのかというと、一見普通のアクセスを装いながら、悪意あるプログラムを送り込んでサイトを乗っ取ろうとする攻撃(クロスサイトスクリプティング等)を防ぐためだ。
ブログの管理画面から <script> という文字列を含むコードを送信する行為は、この攻撃手口と構造が酷似している。
そのため、サーバー側のWAFが「危険な攻撃コードが送信された」と誤検知し、安全のために通信をブロックしたというわけだ。
一見すると厄介なエラーに思えるが、サーバーがサイトを必死に守ってくれている証拠でもあるらしい。
原因さえ分かってしまえば、解決までの手順は極めてシンプルである。
サーバー側で一時的にWAFの検知を無効化し、保存作業を完了させるだけでいい。
まず、利用しているレンタルサーバー(ConoHa WING、エックスサーバー、ロリポップなど)のコントロールパネルにログインする。
セキュリティ設定の項目にある「WAF設定」を開く。
対象ドメインのWAF機能を「無効(OFF)」に切り替える。
設定がサーバー全体に反映されるまで、数十秒から数分ほど待機する。
WordPressの管理画面に戻り、AdSenseのコードを再度貼り付けて保存を実行する。
WAFの監視が解除されているため、今度は問題なく「設定を保存しました」と表示されるはずだ。
保存が完了したら、サーバーのコントロールパネルに戻ってWAFを即座に「有効(ON)」に戻す。
この戻し作業を忘れるとサイトの防御力が低下したままになってしまうため、必ずその場で元に戻しておきたい(ここだけは絶対にサボってはいけない)。
無事に設定が終わって一段落したのだが、ふと気になった。
そもそも、このたった1行の <script> タグは何をしているのだろうか。
普段何気なくコピペしているコードの裏側を覗いてみることにした。
HTMLにおける <script> タグは、ブラウザにJavaScriptを実行させるための専用タグだ。
AdSenseのコードでは src="<https://pagead2.googlesyndication.com/>..." という属性を使って、Googleのサーバーから最新の配信プログラムを外部読み込みしている。
ブラウザはこのURLからスクリプトを取得し、手元のパソコンやスマホの上でプログラムを展開する。
AdSenseのタグには async という属性が付与されている。
通常のHTML読み込みでは、スクリプトに到達すると画面の描画処理が一時停止してしまう(専門用語でレンダリングブロックと呼ばれる現象だ)。
しかし async を指定しておくと、ブラウザはHTMLの解析と並行して裏でスクリプトをダウンロードする。
ダウンロードが完了した瞬間にスクリプトを実行するため、読者の画面表示を極力待たせない工夫が施されているのだ。
さらに驚かされたのは、この1行のスクリプトが読み込まれた後の挙動だ。
サイトのどこに広告を出すか指定していないにもかかわらず、Googleのシステムは適切な位置へ自動的に広告を挿入してくれる。
その裏側では、極めて高度なブラウザ制御技術が動いている。
スクリプトが実行されると、ブラウザがメモリ上に構築したHTMLの構造木(DOMツリー)を高速で解析する。
DOM(Document Object Model)ツリーとは、文章の階層関係(見出しの中に段落があり、横に画像がある等)を木の枝分かれのように整理したデータのことだ。
スクリプトはページ内の見出しや段落の長さ、画像の配置を細かく計算していく。
なぜこれらを計算するのかというと、文章のど真ん中に広告を割り込ませて読書体験を壊さないためだ。
「大見出しの直前」や「区切りの良い段落の後」など、自然に目に入る最適な隙間をプログラムが自律的に割り出し、広告を差し込んでいる。
ページ全体の広告を一気に読み込むと、データ通信量が跳ね上がりページの動作が重くなってしまう。
そこで活用されているのが Intersection Observer API というブラウザ標準の仕組みだ。
APIとは、あらかじめ用意された便利な機能をプログラムから呼び出すための窓口のようなものである。
このAPIを使うことで、ブラウザは「特定の広告エリアがスマホの画面内に入ったかどうか」を裏で効率よく検知できる。
読者がスクロールして近づいた瞬間にだけ広告データを取得して描画するため、無駄な通信を抑えつつ正確な視認性を測定できるのだ。
スマホで記事を読んでいて、ボタンを押そうとした瞬間に広告が割り込んできて画面がカクッと下にズレてしまい、誤タップした経験はないだろうか。
あの強いストレスの原因は「CLS(Cumulative Layout Shift)」と呼ばれる画面のズレだ。
AdSenseのスクリプトは、広告データが届く前にあらかじめ画面上に「広告が入る予定の席(余白)」を確保しておく。
席を先に確保しておくことで、後から広告が表示されても周囲の文章が押し出されず、画面がカクッと揺れるのを防いでいるのだ。
最近の自分は、AIエージェントにコードを書いてもらったり、設定を自動化してもらったりすることが日常になっている。
エラーが出てもAIに聞けば数秒で解決策が返ってくるし、要領よく作業を終わらせる上では欠かせない存在だ。
しかし、AIが提示してくれた答えをただ鵜呑みにして適用するだけでは、どこか物足りなさを感じるようになってきた。
今回のように、たった1行のコードのエラーをきっかけにして、WAFの防衛理由やDOMツリー、API、画面表示の最適化といったWebの仕組みを自分の頭で分解していく過程は純粋に面白い。
AIという強力な相棒に頼りつつも、土台で動いている仕組みへの知的好奇心は常に持ち続けていたいと思う。
広告を貼るという身近な作業から始まった今回の試行錯誤は、Webの奥深さを再認識させてくれる良い機会となった。

