セキュリティ システムアーキテクチャ

2026年07月28日 · 1 分で読めます · 9 ビュー

Web脆弱性の基礎知識(前編):ユーザー入力が「命令」として解釈されるとき

Web脆弱性の基礎知識(前編):ユーザー入力が「命令」として解釈されるとき

Webアプリケーションの危険な脆弱性のほとんどは、非常に古典的な過ちに行き着きます。それは、システムがユーザーから送られてきたデータと、自分自身の命令を区別できないことです。顧客が検索欄に名前を入力しただけなのに、データベースはその文字列を命令として読んでしまう。誰かがコメントを残しただけなのに、別の利用者のブラウザがそれをJavaScriptとして実行してしまう。

最新版であるOWASP Top 10:2025(2021年版を置き換える版)では、インジェクションはA05に位置していますが、CVE数は依然として全カテゴリ中で最多です。37のCWEにまたがり62,000件を超え、そのうちクロスサイトスクリプティングが30,000件以上、SQLインジェクションが14,000件以上を占めます。順位が下がったのは危険性が減ったからではなく、他のカテゴリが上位に移動したためです。

本記事は、自分が何を守っているのかを理解したい若手エンジニア、QA、プロジェクトマネージャーに向けたものです。

2025-mappings.pngOWASP Top 10:2021から2025へのカテゴリ変更。出典:OWASP Foundation(CC BY-SA 4.0)

1. SQLインジェクション:古典的だが今も現役

URLから受け取ったパラメータを、そのままクエリに連結してしまうケースです。

String query = "SELECT * FROM accounts WHERE custID='" + request.getParameter("id") + "'";

攻撃者が引用符と常に真になる条件を含む文字列を送ると、SQL文の構造が壊れ、1件のはずの結果がテーブル全体になります。そこからデータの窃取、改ざん、削除、ストアドプロシージャの実行へとつながります。

よくある誤解として、ORMを使えば自動的に安全になるわけではない点が挙げられます。OWASPは、開発者がパラメータバインドではなく文字列連結を行った場合、HibernateのHQLでも脆弱になることを明示しています。

対策

第一選択はプレースホルダによるパラメータ化、あるいはORMの安全なAPIの利用です。データとクエリ構造を別の経路で渡します。

PreparedStatement ps = conn.prepareStatement("SELECT * FROM accounts WHERE custID = ?");
ps.setString(1, request.getParameter("id"));

さらに多層防御として、サーバー側での許可リスト方式の入力検証、テーブル名・カラム名・ソート順をユーザーに決めさせないこと(これらはエスケープできません)、アプリケーション用DBアカウントの最小権限化、CI/CDでのSAST/DAST実行が有効です。WAFはあくまで緩和策であり、正しいクエリの代わりにはなりません。

sql-injection-infographic.pngSQLインジェクションの仕組み。出典:Cloudflare Learning Center

2. OSコマンドインジェクション:SQLiよりも深刻

ユーザー入力をOSコマンドに連結している場合(例:ドメイン確認機能がnslookupを呼び出す)、攻撃者はコマンド区切り文字を加えるだけで任意のコマンドを実行できます。サーバー全体を失う最短経路です。

対策:ライブラリで実現できるならシェルを呼ばない。どうしてもプロセスを起動する場合は、単一の文字列ではなく引数配列で渡し、シェルを経由させない。厳格な許可リストで入力を検証する。制限されたコンテナ内で最小権限のまま実行する。

3. クロスサイトスクリプティング(XSS):利用者のブラウザで動く攻撃コード

XSSは、ユーザー入力が適切にエンコードされないままHTMLとして出力されると発生します。主に3種類あり、格納型(DBに残り、閲覧者全員が影響を受ける)、反射型(細工されたリンク経由)、DOMベース(クライアント側JavaScriptが信頼できないデータをDOMに書き込む)に分かれます。典型的な被害はセッションの窃取、利用者になりすました操作、偽ログインフォームの挿入です。

対策

基本原則は出力コンテキストに応じたエスケープです。HTML本文、属性値、JavaScript、URLではそれぞれ必要な処理が異なります。React、Vue、Angular、Bladeなどの現代的なフレームワークは既定でエスケープしますが、問題はinnerHTMLやv-html、dangerouslySetInnerHTMLで開発者が意図的にその保護を外すことです。ユーザー入力のHTMLを表示する必要がある場合は、正規表現で自作するのではなくDOMPurifyのような専用ライブラリで無害化します。

加えて、Content-Security-Policyヘッダーで不正なスクリプトを遮断し、セッションCookieにHttpOnly属性を付与してJavaScriptからトークンを読めなくすることが有効です。

xss-attack.pngXSS攻撃の流れ。出典:Cloudflare Learning Center

4. SSRF:サーバーを攻撃者の代理としてリクエストさせる

SSRF(Server-Side Request Forgery)は、ユーザーが指定したURLへアプリケーション自身がリクエストを送る機能で発生します。URLからの画像取り込み、Webhook、HTMLからPDFへの変換などが典型です。攻撃者は内部アドレスを指定し、インターネットからは到達できない内部サービス、一時的な認証情報を返すクラウドのメタデータエンドポイント、社内限定の管理画面などを狙います。

注目すべき点として、2025年版でOWASPはSSRFをA01 Broken Access Controlに統合しました。これは本質を突いた分類で、SSRFは信頼境界の侵害だからです。

対策:ブロックリストではなく、事前承認したドメイン/IPのみを許可する。接続前にDNSを解決して宛先IPを検証し、内部レンジを拒否する。リダイレクトを自動追跡しない。取得処理を内部へアクセスできないサブネットの別サービスに分離し、ネットワーク層でegress制御を行う。

5. パストラバーサルとファイルアップロード

無害に見えて見落とされがちな2つの機能です。ユーザー指定のファイル名でダウンロードさせる処理では、上位ディレクトリへの参照によって設定ファイルや秘密鍵が読まれる恐れがあります。アップロードでは、実行可能ファイルを置かれて呼び出されるリスクがあります。

対策:ユーザー指定のファイル名をパスに連結しない。ランダムな名前を生成し、対応関係はDBで管理する。パスを正規化し、許可されたルート配下にあることを検証する。拡張子やContent-Typeではなく実際の内容でファイル種別を判定する。ファイルは別のオブジェクトストレージに保存し、別ドメインから配信し、アップロード先での実行を禁止する。

6. プロンプトインジェクション:同じ問題の2026年版

チャットボットやRAGパイプラインを提供しているなら、OWASPがLLM向けTop 10でLLM01:2025 Prompt Injectionを独立して扱っている点を押さえておくべきです。本質は従来のインジェクションと同じで、モデルはシステム指示とユーザー入力、取得した文書の内容を区別できません。さらに厄介なのが間接型で、悪意ある指示がボットの参照する文書側にあらかじめ仕込まれているケースです。

緩和策:モデルの出力は信頼できないデータとして扱い、SQLやシェル、HTMLへ直接渡さない。エージェントが呼び出せるツールの権限を最小化する。実世界に影響する操作は人間の承認を必須にする。システム指示と取得コンテンツの境界を明示する。調査できるようプロンプトとツール呼び出しをすべてログに残す。

プルリクエストをマージする前のチェックリスト

  • すべてのDBクエリがパラメータ化され、文字列連結が残っていない。
  • OSコマンドにユーザー入力を連結している箇所がない。
  • 画面に出力されるデータがコンテキストに応じてエスケープされている。
  • Content-Security-Policyを設定し、セッションCookieにHttpOnlyを付与している。
  • サーバーが呼び出すURLはすべて許可リストを通している。
  • ファイルパスを正規化し、許可ディレクトリ内に限定している。
  • 検証がクライアント側フォームだけでなくサーバー側でも動作している。
  • CIにSASTと依存関係スキャンが組み込まれている。

まとめ

前編の要点は一つです。データと命令を分離し、クライアントからの入力を決して信用しないこと。後編では、見えにくいがより高くつく脆弱性——アクセス制御、認証、設定ミス、ソフトウェアサプライチェーン——を取り上げます。

参考文献

ビジネス変革の準備はできていますか?

AIとデジタル変革の活用について、ぜひご相談ください。

シェア