トップ›実践編›第11章
実践編第11章

演習3:入力欄の安全確認

読む目安:約40分入力欄に無害な文字列を入れ、命令として解釈されないかを見る

入力欄は、外の世界からあなたのアプリに「文字を送り込める口」です。その文字が、データとしてではなく命令として扱われてしまうと、データベースが思わぬ動きをしたり、他の利用者の画面で勝手なプログラムが動いたりします。この章では、仕組みを図で理解したうえで、無害な文字列だけを使って自分のアプリの入力欄を確かめます。

この章の学習目標

  • インジェクションとクロスサイトスクリプティング(XSS)が「データと命令の混同」であることを、図で説明できるようになる
  • 無害な文字列(太字タグ、長い文字列、全角数字など)で、自分のアプリの入力欄の扱いを確かめられるようになる
  • 「安全な方法を使っているか」をAIに確認させ、その報告を自分で読めるようになる

入力欄は「命令を送り込める口」

伝票の摘要欄を思い浮かべてください。そこに書かれた文字が、会計システムに取り込まれたとき、文字としてではなく「この仕訳を削除せよ」という命令として実行されてしまったらどうなるでしょう。摘要欄に書けるのは起票者です。起票者が会計システムに命令できることになってしまいます。入力欄の安全確認とは、「摘要欄の文字は、どこまで行っても文字のまま扱われるか」を確かめることです。

論文で2位だった「インジェクション」(199件、16.78%)は、まさにこの問題です。インジェクション(injection。注入)とは、利用者が入力した文字が、サーバーがデータベースなどに送る命令の一部に混ざり込み、命令の意味が変わってしまうことを指します。

もうひとつ、XSS(クロスサイトスクリプティング)という不備があります。こちらは、入力した文字が他の利用者の画面にそのまま表示され、ブラウザがそれを「実行するプログラム」として解釈してしまうものです。OWASP Top 10:2025では、XSSはA05「インジェクション」の一種として分類されています。

入力欄 利用者が書いた文字 サーバー 文字を受け取って処理 データベースへの命令 文字が命令に混ざる → インジェクション 守り:命令とデータを分けて渡す 他の利用者の画面 文字がそのまま表示される → XSS 守り:表示するときにエスケープする 「文字は文字のまま」を サーバーと画面の両方で守る
図11-1 入力した文字が「命令」に化ける2つの経路。上がインジェクション、下がXSSです。どちらも守り方は「文字を命令と混ぜない」ことに尽きます。

守り方は「混ぜない」と「そのまま出さない」

対策は、攻撃の種類を暗記することではありません。次の2つの原則が守られていれば、ほとんどのインジェクションとXSSは成立しません。

命令とデータを分けて渡す

データベースへの命令を文字のつなぎ合わせで組み立てる代わりに、「命令の型」と「はめ込むデータ」を別々に渡す方法があります。プレースホルダー付きのクエリ(パラメータ化クエリ)と呼ばれ、OWASPのSQL Injection Prevention Cheat Sheetが第一の対策として挙げているものです。Supabaseのクライアントライブラリや、一般的なORM(データベースを扱う部品)は、通常この方式で動きます。危ないのは、AIが「SQLを文字列でつなげて作る」コードを書いた場合です。

表示するときにエスケープする

利用者の入力を画面に出すとき、< や > のような記号を、ブラウザが「タグ」と解釈しない形に変換することをエスケープと呼びます。Reactをはじめ多くのフレームワークは、標準でこれを行います。例外は、「HTMLをそのまま挿入する」ための機能を使った場所です。Reactなら dangerouslySetInnerHTML という、わざわざ危険だと名前に書いてある機能がそれに当たります。AIはリッチな表示を実現するために、これを気軽に使うことがあります。

入力の検証は補助

長さ、形式、文字種の確認(検証)も大切ですが、これは上の2つの代わりにはなりません。検証は「おかしな入力を早めに弾く」ための補助であり、本体は「混ぜない」「そのまま出さない」です。IPAの「安全なウェブサイトの作り方」でも、SQLインジェクションとクロスサイト・スクリプティングは代表的な脆弱性として取り上げられ、根本的解決と保険的対策が分けて説明されています。

ここはAI任せにできない:Veracodeの数字

基礎編で触れたVeracodeの「2025 GenAI Code Security Report」を、ここでもう一度引きます。100以上のLLMに80種類の課題を解かせたところ、全体の45%でOWASP Top 10相当の脆弱性が入りました。種類別に見ると、XSS(CWE-80)は86%、ログインジェクション(CWE-117)は88%のケースで防げていません。しかも、新しいモデルでも安全性はほぼ横ばいでした。

AIは「エスケープが必要な場所」を高い確率で見落とす、ということです。文法的には正しく動くコードなので、本人(AI)も持ち主も気づきません。入力欄の確認は、人の目で、自分のアプリに対して、必ず一度はやっておく必要があります。

無害な確認方法

この章で使う確認方法は、すべて「普通の文字を入れてみて、普通に表示されるか」です。攻撃用の文字列を集めて試す必要はありませんし、やるべきでもありません。それは専門家が契約のもとで行う作業(ペネトレーションテスト)であり、自分のアプリであってもデータを壊すことがあります。

  • 太字タグ。名前やメモなど、普通の文字だけを入れる欄に <b>テスト</b> と入力して保存します。一覧や詳細画面で「テスト」が太字になったら、入力がHTMLとして解釈されています。普通の文字欄なら、エスケープ不足の印です。正しい状態は、<b>テスト</b> という文字がそのまま見えることです。ただし、太字や見出しを使える「リッチテキスト」の欄は、もともとHTMLを表示する設計なので、太字になるのは正常です。そうした欄の安全性は、危険なタグを取り除く処理(サニタイズ)があるかで決まり、この方法では確かめられません。また、ある画面で文字のまま表示されても、同じ値が出る別の場所(メール本文、管理画面、検索結果など)も安全とは限りません。この確認は「明らかな見落としを見つける」ためのもので、合格しても「XSS対策は完璧」という証明にはなりません。
  • 極端に長い文字列。同じ文字を数千文字入れて保存します。画面が崩れる、エラー画面に内部情報(ファイル名やSQLの断片)が出る、保存に長時間かかる、のいずれかなら要対応です。
  • 空、空白だけ、改行だけ。必須欄が空で通るか、空白だけで通るかを見ます。
  • 全角数字、絵文字、記号。金額欄に「123」、名前欄に絵文字や「&」「'」「"」を入れます。壊れずに保存・表示されるか、あるいは丁寧に拒否されるかを見ます。
  • ファイルアップロードがあるなら、許可する拡張子とサイズの上限が決まっているか、アップロードしたファイルが誰でも開けるURLに置かれていないかを見ます。

いずれも、入れるのは自分のテスト用アカウントのデータに対してだけです。結果は点検ノートに「入れたもの」「表示された結果」「問題の有無」を書きます。

注意:他人のサイトの入力欄で試さない 太字タグを入れるだけの無害な確認でも、他人のサイトやサービスで行えば、相手にとっては「脆弱性を探られた」ことになります。不正アクセス禁止法や業務妨害に当たるおそれがあり、善意でも許されません。自分のアプリに対してだけ行ってください。
AIへの頼み方(入力経路のレビュー)
このリポジトリで、利用者からの入力を受け取るすべての経路を列挙し、それぞれの安全性をレビューしてください。

対象:フォームの入力欄、URLのパラメータ、APIが受け取るデータ、ファイルアップロード、外部サービスから受け取るデータ。

それぞれについて、次を表にしてください。
1. 経路の名前とファイル名、行番号
2. その入力がデータベースへの命令に使われる場合、プレースホルダー付きのクエリ(パラメータ化)やORMを使っているか。SQLを文字列連結で組み立てている箇所があれば指摘
3. その入力が画面に表示される場合、フレームワークの標準のエスケープで表示しているか。HTMLをそのまま挿入する機能(dangerouslySetInnerHTML など)を使っている箇所があれば指摘
4. 長さ・形式・文字種の検証をサーバー側で行っているか
5. ファイルアップロードがある場合、拡張子・サイズ・保存先の制限
6. エラーが起きたとき、利用者の画面に内部情報(スタックトレース、SQL、ファイルパス)が出ないようになっているか

問題のある箇所を深刻な順に並べてください。
攻撃用の文字列の例は出力しないでください。
修正はまだしないでください。報告だけお願いします。

演習3:入力欄の安全確認

所要時間:約25分
  1. 第8章の全体図から、入力欄のある画面をすべて点検ノートに書き出します。検索欄、ログイン欄、設定画面も忘れずに入れます。
  2. 上の定型文でAIにレビューさせ、「文字列連結」「HTMLをそのまま挿入」「検証なし」と指摘された箇所を点検ノートに写します。
  3. 自分のテスト用アカウントでログインし、書き出した入力欄のそれぞれに <b>テスト</b> を入れて保存し、その値が表示される画面をすべて確かめます。普通の文字欄で太字になったものを記録します。リッチテキストの欄は「この方法では判定できない」と記録し、サニタイズの有無をAIのレビューで確かめます。
  4. 同じ欄に、数千文字の文字列、空白だけ、全角数字、絵文字を順に入れ、壊れずに保存・表示されるか、または丁寧に拒否されるかを記録します。
  5. エラーが出た場合、その画面に内部情報が出ていないかを見ます。出ていれば第12章の対象でもあります。
  6. ファイルアップロードがあれば、拡張子とサイズの制限、保存先のURLが誰でも開けるものでないかを確かめます。
  7. 記録した問題を「要対応」として点検ノートに残し、第13章で修正したあと、手順3から再確認します。

まとめ

  • インジェクションもXSSも、入力した「文字」が「命令」として扱われる問題。論文では2位(199件、16.78%)。摘要欄の文字が会計システムの命令になってはいけないのと同じ。
  • 守り方は2つ。データベースへは命令とデータを分けて渡す(プレースホルダー付きのクエリ)。画面に出すときはエスケープする(フレームワークの標準に任せ、HTMLをそのまま挿入する機能を避ける)。
  • VeracodeによればAIはXSSを86%防げなかった。ここは人の目で、無害な文字列(太字タグ、長い文字列、全角数字)を自分のアプリに入れて確かめる。他人のサイトでは試さない。

出典