この記事でわかること
- 自分の PC の中だけで、PHP の脆弱性を体験できる練習用の環境の作り方(Windows・管理者の権限なし)
- SQL インジェクションと XSS が「どう起きて、どう直すか」を、危ない例と直した例を並べて体験する手順
- 新人研修で使うときの進め方と、AI(Claude Code)にコードを見てもらう方法
対象:Web の開発をはじめたばかりの新人エンジニアと、研修を担当する人/Windows 11・PHP 8.4.27 で確かめた手順/所要時間:準備15分+体験30分
先に答えを書きます。PHP 公式の Windows 用 zip を展開し、設定ファイルで SQLite(ファイル1つで動くデータベース)を有効にすれば、インストールも管理者の権限もなしに練習用の環境が作れます。本記事で配っている練習用ファイル(わざと危なく作った例と、直した例)を置いて、PHP に入っている小さな Web サーバーを自分の PC からしか見えない設定で起動すれば準備完了です。入力欄に1文字入れるだけで、危ない例が壊れる様子と、直した例では何も起きない様子を見比べられます。
はじめる前に、必ず守ること
- 自分の PC の中だけで動かす:Web サーバーは
127.0.0.1(自分の PC だけを指す住所)で起動し、ほかの PC から見えるようにしない - ほかの人のサイトやシステムでは絶対に試さない:許可なく他人のシステムで試すと、不正アクセス禁止法などの法律に触れることがあります
- 練習用のファイルを本番や社内のサーバーに置かない:わざと危なく作ってあります
- 会社の PC で試すときは、先に上司や情報システムの担当に確認する
- 終わったら片付ける:フォルダを消せば元に戻ります
このハンズオンで体験すること
| 脆弱性 | 何が起きるか | 直し方 |
|---|---|---|
| SQL インジェクション | 入力した文字が、データベースへの命令(SQL)の一部として扱われてしまう。見えてはいけないデータを読まれたり、消されたりする | プレースホルダを使い、入力は「値」としてだけ渡す |
| XSS(クロスサイトスクリプティング) | 入力した文字が、ページの HTML の一部として扱われてしまう。見ている人のブラウザで、他人のプログラムを動かされる | HTML に出す前に htmlspecialchars で「ただの文字」に変える |
どちらも原因は同じで、「入力された文字を、そのまま命令や HTML の一部として使っている」ことです。Web アプリの脆弱性の中でも代表的なもので、情報処理推進機構(IPA)の「安全なウェブサイトの作り方」でも、最初のほうに取り上げられています。
準備1:PHP を用意する(インストール不要)
- PHP 公式の Windows 版のページ(windows.php.net/download)を開き、PHP 8.4 の「VS17 x64 Non Thread Safe」の Zip をダウンロードします(筆者が試したのは
php-8.4.27-nts-Win32-vs17-x64.zip・約34MB) - 同じページには、ファイルごとに SHA256 という「指紋」の値が載っています。PowerShell で次を実行し、出てきた値がページの値と同じなら、途中で壊れたり差し替えられたりしていない本物です
cd $HOME\Downloads
Get-FileHash .\php-8.4.27-nts-Win32-vs17-x64.zip -Algorithm SHA256確かめたら、ユーザーフォルダの中の php フォルダに展開し、動くかを確かめます。
Expand-Archive .\php-8.4.27-nts-Win32-vs17-x64.zip -DestinationPath $HOME\php
& "$HOME\php\php.exe" -v
筆者の PC では、1行目に PHP 8.4.27 (cli) と出ました。「VCRUNTIME140.dll が見つからない」のようなエラーが出たときは、PHP を動かすのに必要な Microsoft の部品(Visual C++ 再頒布可能パッケージ)が入っていません。PHP 公式のページにも、この部品が必要だと書かれています。Microsoft の公式サイトから入れてください。
準備2:設定ファイルで SQLite を有効にする
展開したばかりの PHP では、データベースの SQLite を使う機能が有効になっていません。PHP に入っている開発用の設定の見本をコピーして、3か所を書き換えます。
Copy-Item $HOME\php\php.ini-development $HOME\php\php.ini
notepad $HOME\php\php.iniメモ帳で開いたら、Ctrl+F で次の3つの行を探し、行の先頭の ;(この行を無効にする印)を消して保存します。
extension_dir = "ext"
extension=pdo_sqlite
extension=mbstringextension_dir は同じ名前の行が2つあります。"ext" と書かれたほうです。保存したら、次のコマンドで有効になったかを確かめます。
& "$HOME\php\php.exe" -m | Select-String pdo_sqlite
pdo_sqlite と表示されれば成功です。何も出ないときは、3行の ; が消えているか、ファイル名が php.ini になっているかを見直します。
準備3:練習用ファイルを置いて、起動する
練習用ファイル一式を zip にまとめました。中身は、データベースを作る setup.php、危ない例と直した例が2組、説明の README.txt です。データはすべて架空のものです。
ダウンロードしたら、展開してデータベースを作り、Web サーバーを起動します。
cd $HOME\Downloads
Expand-Archive .\fcn-php-security-lab-v2.zip -DestinationPath $HOME
cd $HOME\php-security-lab
& "$HOME\php\php.exe" setup.php
& "$HOME\php\php.exe" -S 127.0.0.1:8080
4行目で lab.db を作りました(3件) と出て、5行目のあとは PowerShell が止まったように見えます。これは Web サーバーが動いている状態です。この画面は閉じずに、ブラウザで次のページを開きます。
http://127.0.0.1:8080/search_bad.php(危ない検索)http://127.0.0.1:8080/search_good.php(直した検索)http://127.0.0.1:8080/hello_bad.php(危ない表示)http://127.0.0.1:8080/hello_good.php(直した表示)
127.0.0.1 は「この PC 自身」を指す特別な住所です。ここで起動すると、同じネットワークのほかの PC からは見えません。PHP の公式マニュアルでも、この Web サーバーは開発用で、公開するサーバーには使わないように書かれています。
体験1:SQL インジェクション
まずはふつうに検索する
search_bad.php を開き、検索欄に「田中」と入れて検索します。田中さんの部署が表示されます。このページは学ぶために、実際に実行した SQL(データベースへの命令の文)も画面に出しています。

「’」を1文字だけ入れてみる
次に、検索欄に半角の「'」(シングルクォート)を1文字だけ入れて検索します。すると、エラーが出ました。

「'」は、SQL の文の中で「ここからここまでが文字」という区切りの印です。入力した「'」がそのまま SQL の文に入ったので、区切りの数が合わなくなり、文として壊れました。入力が「値」ではなく、命令の文の一部として読まれている証拠です。
このハンズオンでは、壊れる様子を見るところで止めます。本当の攻撃では、この性質を使って命令の文を書き換え、本来は見えないデータまで読み出します。練習用のデータベースにも、表示されないはずの「社外秘のメモ」が入れてあります。こうしたデータが、入力欄ひとつから読まれてしまうのが SQL インジェクションです。
原因のコード

6行目で、入力された名前を、SQL の文の文字列に「.」でそのままつなげています。15行目で、その文をそのまま実行しています。入力に何が入っていても、文の一部になってしまいます。
直した例:プレースホルダを使う

6行目では、SQL の文の中で値が入る場所を ?(プレースホルダ)にして、先に文の形だけを準備しています(prepare)。13行目の execute で、入力を値として別に渡しています。こうすると、入力に「'」が入っていても、ただの文字として扱われます。search_good.php で同じように「'」を入れると、エラーにならず「見つかりませんでした」と出るだけです。

体験2:XSS(クロスサイトスクリプティング)
HTML のタグを入れてみる
hello_bad.php を開き、入力欄に <b>太字</b> と入れて「表示」を押します。<b> は文字を太くする HTML のタグです。すると、入力したタグは表示されず、「太字」の文字が本当に太字になりました。

入力した文字が、ページの HTML の一部として読まれた証拠です。太字なら害はありませんが、本当の攻撃では、ここにプログラム(JavaScript)を入れます。その仕掛けを入れたリンクを開いた人のブラウザで、他人のプログラムが動き、ログインの情報を盗まれたり、にせの入力画面を出されたりします。
原因のコードと、直した例

8行目で、入力をそのまま HTML の中に出しています。直した例では、出す前に htmlspecialchars という関数を通しています。

htmlspecialchars は、< や >、" などの HTML で特別な意味を持つ記号を、画面に記号として表示するための書き方に置き換えます。hello_good.php で同じものを入れると、タグがそのまま文字として表示されました。

やってみよう:Claude Code に危ないコードを見てもらう
自分で書いたコードに同じ問題がないかを確かめるのに、AI に見てもらう方法もあります。練習用のフォルダで Claude Code を起動し、次のように頼みました。
このフォルダの search_bad.php と hello_bad.php に、セキュリティ上の問題がないか確認してください。問題があれば、何が起きるか・どの行か・どう直すかを、新人エンジニアにもわかる言葉で教えてください。ファイルは変更しないでください。返ってきた指摘をまとめると、次のとおりです(返事には攻撃の入力の例も書かれていましたが、記事では省いています)。
| ファイルと行 | 指摘 | 直し方 |
|---|---|---|
| search_bad.php の6行目(実行は15行目) | SQL インジェクション(重大) | prepare と ? を使う |
| search_bad.php の11行目・19行目 | 実行した SQL やデータベースのエラーの詳細を画面に出している。攻撃のヒントになる | 本番では出さず、決まった文言だけを出して、詳細はログに残す |
| hello_bad.php の8行目 | XSS(重大) | htmlspecialchars を通してから出す |
どの行が問題か、なぜ危ないか、どう直すかまで、正しく答えてくれました。さらに、学ぶためにわざと画面に出していた「実行した SQL」や「エラーの詳細」も、本番では攻撃のヒントになると指摘しています。ただし、AI の指摘がいつも正しく、全部を見つけてくれるとは限りません。指摘を読んで「なぜそうなるか」を自分で説明できるかを確かめる、という使い方がおすすめです。Claude Code の始め方は「Claude Code の教科書」で解説しています。
新人研修で使うときの進め方(30分の例)
| 時間 | やること |
|---|---|
| 5分 | 守ることの説明(自分の PC だけ・他人のシステムでは試さない) |
| 10分 | 体験1・体験2で、危ない例が壊れる様子と、直した例を見比べる |
| 10分 | 課題:hello_bad.php を自分で直し、<b> が文字として出るかを確かめる |
| 5分 | ふり返り:「入力をそのまま命令や HTML に使わない」を、自分の言葉で説明する |
課題は、直した例の hello_good.php を見ずに取り組んでもらい、終わってから見比べると身につきやすくなります。setup.php を実行し直せば、データベースはいつでも最初の状態に戻ります。
終わったら片付ける
- Web サーバーを動かしている PowerShell で Ctrl+C を押して止める
- エクスプローラーで、ユーザーフォルダの
php-security-labフォルダを消す - PHP をもう使わないなら、
phpフォルダも消す(インストールしていないので、これで元に戻ります)
会社でみんなの環境をそろえるなら
研修の参加者が多いときは、Docker(同じ環境を箱のようにまとめて配れる道具)で環境をそろえる方法もあります。ただし Docker Desktop を Windows に入れるには、管理者の権限や WSL の準備が要ることが多く、そこでつまずく新人も少なくありません。まずは本記事の zip の方法で始め、慣れてきたら Docker にする、という順番がおすすめです。
よくある質問
自分の PC で試すのは、法律的に問題ありませんか?
自分の PC で、自分が置いた練習用のファイルに対して試すぶんには、他人のシステムに入ることにはなりません。問題になるのは、許可なくほかの人のサイトやシステムで試すことです。会社の PC や社内のネットワークで試すときは、会社のルールにしたがい、先に担当者に確認してください。
ウイルス対策ソフトに止められることはありますか?
筆者の PC では止められませんでした。会社の PC では、セキュリティの設定によって、PHP の実行や Web サーバーの起動が止められることがあります。その場合は無理に回避せず、担当者に相談してください。
ほかの脆弱性も体験できますか?
同じ作り方で、ほかの脆弱性の練習用ファイルも作れます。まずは、もっとも基本的な2つ(SQL インジェクションと XSS)で「入力をそのまま使わない」という考え方を身につけるのがおすすめです。
参考資料
- 安全なウェブサイトの作り方(情報処理推進機構・IPA。代表的な脆弱性と対策)
- プリペアドステートメントおよびストアドプロシージャ(PHP マニュアル。プレースホルダの使い方)
- htmlspecialchars(PHP マニュアル)
- ビルトインウェブサーバー(PHP マニュアル。開発用の Web サーバー)
- PHP For Windows(PHP 公式。Windows 用の zip と、必要な Visual C++ の部品)
確かめた日と環境:2026年10月26日、Windows 11 Pro/PowerShell 5.1/PHP 8.4.27(公式 zip・SHA256 が公式の値と一致することを確認)で、本記事の練習用ファイルを実際に動かしました。画面の画像は、自分の PC の中だけで動かした練習用ページを撮ったものです。Claude Code の指摘は Claude Code 2.1.302(Max プラン)で claude -p を1回実行した結果をまとめたもので、同じ依頼でも答えは毎回少しずつ違うことがあります。
改訂履歴:2026年10月26日 公開(同日、準備の手順に PowerShell の表示の画像を3枚追加)
本記事は、脆弱性のしくみと対策を学ぶための教材です。ほかの人のシステムで試すことは目的としていません。記事の作り方は制作方針をご覧ください。

コメント