Blade – GMO Developers https://developers.gmo.jp 「GMO Developers」は GMOインターネットグループの開発者向け情報をお届けしています。 Sun, 13 Jul 2025 23:51:11 +0000 ja hourly 1 攻めと守りで理解するPHPアプリケーションのセキュリティ:生成AI時代のXSSとその対策 https://developers.gmo.jp/technology/66864/ Mon, 14 Jul 2025 01:00:00 +0000 https://developers.gmo.jp/?p=66864

 本記事は、PHPカンファレンス2025でのスポンサーセッションに登壇した@k1rnt(てぃー)氏のセッション「攻めと守りで理解する PHP アプリケーション」書き起こしレポートです。

はじめに

生成AIがソースコードを提案・生成する時代に入り、Webアプリケーションのセキュリティ対策にも新たな視点が求められています。今回はPHPカンファレンス2025におけるスポンサーセッション「攻めと守りで理解する PHP アプリケーション」より、生成AIのコード提案に潜むセキュリティリスクとその対策について解説します。XSSの実例やLaravel Bladeにおける注意点、AI時代のセキュアコーディングの心得などを通じて、開発者に求められる「攻め」と「守り」の視点を紹介いたします。
生成AIの活用が広がる中で安全なWeb開発を実現するためのヒントとなれば幸いです。

AIが書いたコードに潜む罠

てぃーさんは、AIによって作成されたPull Requestを確認するところからセッションをスタートします。

$input = $_GET['comment'] ?? '';
$escaped = htmlspecialchars($input, ENT_QUOTES, 'UTF-8');
$allowedTags = ['b', 'i'];
foreach ($allowedTags as $tag) {
$escaped = preg_replace("/<\/?$tag.*?>/i", '', $escaped);
}
echo $escaped;

「bタグとiタグだけを許可したい」という意図のコードですが、preg_replace の置換処理によって、エスケープされた文字列から、 <b>と<i> タグが再びタグとして扱われています。 よって、次のようなペイロードではXSSが発生します。

これは、ブラウザに <b>タグがそのまま残り、onclick 属性に埋め込んだ JavaScript が実行されます。

<b onclick="alert(1)">click</b>

この例から学べるのは、AIが生成する「それっぽいコード」には、意図しない脆弱性が埋め込まれる可能性があるということです。

フレームワーク依存はもう危ない?

てぃーさんは次のように警鐘を鳴らします。

てぃー

「これまではフレームワークが脆弱性から守ってくれていたが、AIが生成するコード量が圧倒的に多くなることで、レビュー時に見逃す危険性が生まれています」

つまり、今後は「攻撃者視点」を持ち、脆弱性を見逃さない能力がより重要になっていくのです。

Bladeテンプレートの盲点

Laravelにおいてよく使われるBladeテンプレート。次の2つの出力方法があります。

  • {{ $var }}:自動エスケープされる
  • {!! $var !!}:非エスケープでそのままHTMLとして出力

この違いが、XSSが発生するリスクに繋がります。

危険な事例

<div>
  {!! $content !!}
</div>

ここで $content にユーザー入力が入っていると、<script><img onerror=...> などのタグがそのまま出力され、XSSが成立します。

安全な事例

<div>
  {{ $content }}
</div>

{{$content}} は自動的に htmlspecialchars() を通してくれるため、基本的にはXSSが起こりません。ただし、Htmlable インターフェースを実装したクラス(例:HtmlStringなど)を渡すと、{{$content}} であってもスルーされてしまうことがあります。

Unicode正規化によるXSS:文字変換の罠

LaravelやPHPのアプリケーションでは、「café → cafe」のように文字列の正規化(Normalization)を行うことがあります。しかし、これがXSSの入り口になることもあります。

エスケープ済なのでXSSも発生しません。

一見エスケープされているので安全そうですが、«svg/onload%3Dalert(1)»を入力すると・・

なぜ起こるのか?

  • 入力された値は一度エスケープされます。しかしそのあとに以下のように文字列が操作されるため、XSSが発生します。
  • %C2%AB«(U+00AB)、%C2%BB»(U+00BB)を表す
  • ASCIIに変換すると << および >> に変換される
  • 結果的に <svg> タグとしてHTMLに解釈され、XSSに繋がる

対策

  • エスケープは出力直前に行う
  • エスケープ後の文字列に対しては文字変換・正規化を行わない

CSPは有効だが万能ではない

セッション終盤では、CSP(Content Security Policy)を設定してもXSSを完全に防げるわけではないという例も登場しました。

header("Content-Security-Policy: default-src 'none';");
if (isset($_GET['xss'])) echo $_GET['xss'];

このように設定していても、$_GETのパラメータ数が、max_input_vars(デフォルトでは1000)を超えると、max_input_varsの上限を超えることで出力される警告が出力されます。その時、header() 関数はキューに入り、CSPヘッダーより先に警告やその他の出力が行われるといった仕様があります。

そのため、以下のようなペイロードでXSSが発火してしまいます。

document.location = '/?xss=&'+'a=x&'.repeat(1000)



CSPは有効な対策です。ですが、現状のPHPでは上記のようなバイパスができる仕様になっているので、CSPに完全に依存するのではなくエスケープを適切に行うことが重要です。

攻めと守りの両輪でセキュアに

最後にてぃーさんは次のようなポイントを強調しました。

  • 出力前にエスケープを行う
  • サニタイズが必要なら信頼できるライブラリ(例:mewebstudio/Purifier)を使う
  • エスケープ後に文字列操作をしない
  • CSPを適切に設定する

さいごに

このセッションは、「フレームワークを使っていても使い方によっては脆弱性が発生する場合がある」「AIコードを鵜呑みにしてはいけない」という、現代的な開発環境への強いメッセージに満ちていました。

攻め(攻撃者目線)と守り(防御者目線)の両輪で、PHPアプリケーションを理解すること。

それが、今この時代にセキュリティエンジニアとして、あるいは開発者として生き残るために必要な視点なのかもしれません。

登壇資料についてはこちらに公開されておりますので、ご参照ください!

]]>