初級では「外から来た値を、そのまま使わずに確かめる」を土台としました。中級では、何を・どこで・どの順で確かめるかを整理します。
概要 — まず全体をつかむ
詳細 — 1段階ずつ追う
なぜ必要?
ブラウザから届く値・URLのパラメータ・アップロードファイル・APIのリクエストボディ——これらはすべて信頼境界の外から来ます。攻撃者が自由に作れる以上、そのまま処理へ流すと XSS や SQLインジェクションの入口になります。
ポイントは、検証は信頼境界を越える所で行うこと。外の値が内側のロジックへ入る手前に「関所」を置きます。
やさしく言うと(初級)
ブラウザから届く値・URLのパラメータ・アップロードされるファイル——これらは攻撃者が自由に作れるものです。そのまま使うと、XSSやSQLインジェクションなどの穴になります。だから、まず疑って確かめます。
どう確かめる?
検証の観点を、緩い順ではなく絞り込む順に重ねます。
- 型 — 数値・真偽・日付など、期待する型か
- 長さ — 上限・下限。極端に長い入力はそれ自体が攻撃の兆候
- 範囲 — 数値や日付が想定の区間に収まるか
- 形式 — メール・電話・IDなど、決まった形に合うか
- 許可リスト > 拒否リスト — 最後は「通してよいものだけ通す」に寄せる
アニメーション『入力検証=関所』を開く
正規化を先に、検証を後に。 全角/半角、大文字/小文字、Unicodeの合成形などの表記ゆれを揃えてから検証します。順序を逆にすると、検証後に別の形へ化けて許可リストをすり抜けられます。
そして最重要は、サーバ側で必ずやること。フロントの検証は UX 補助(入力ミスへの親切)であって、防御ではありません。攻撃者はフロントを無視して直接サーバへ送れます。
登場人物メモ:
- ※1 信頼境界 — 信用できる領域と、できない領域の境目。検証はこの境界で行う
- ※2 正規化 — 表記ゆれを揃え、比較・検証できる形にそろえる前処理
この部分をもっと深く(上級)
「危ないものを弾く」拒否リストは、攻撃者の発想力との追いかけっこになります。設計思想として弱いのは、次の非対称性のためです。
- 拒否リストは「既知の悪い形」を数え上げる。新しい表現・エンコード・記号の組み合わせが出るたびに穴が空く。守る側が全パターンを先回りするのは原理的に難しい
- 許可リストは「既知の良い形」だけを通す。想定外はすべて弾くので、未知の攻撃表現も自動的に落ちる
- 実務では構造化して絞るのが強い。「英数字4〜32文字」より「
^[a-z0-9_]{4,32}$に一致」、さらに「区分値は列挙した候補のいずれか」——形式・集合・型で閉じるほど、すり抜けの余地が消える ※1
アニメーション『入力検証=関所』を開く
やさしく言うと(初級)
- 型 — 数値のはずが文字列でないか
- 範囲・長さ — 想定の範囲に収まっているか(年齢が -1 や 9999 でないか)
- 形式 — メールの形、日付の形など
- 許可リスト — 「許可するものだけ通す」(危ないものを列挙するより安全)
入力検証は、外から来た値を確かめる「関所」です。通ったものだけ処理へ進み、怪しいものは弾きます。
アニメーション『入力検証=関所』を開く
そして最重要は、サーバ側で必ずやること。フロントのチェックは利用者への親切であって、防御ではありません。
検証と無害化は別物
検証(入口) と 出力エスケープ(出口) は役割が違います。
- 検証 — 想定外の値を「弾く」。入口の関所
- 出力エスケープ — 通した値を、出す先(HTML・SQL・URL)で「無害化」する。出口の変換
検証を通った値でも、出力の文脈しだいで危険になります。だから両方が必要で、片方では守れません。
この部分をもっと深く(上級)
三つは似て見えて役割が違います。混同すると「片方だけで安心」する事故が起きます。
- 検証(入口) — 想定した「形」かを確かめ、外れたら弾く。値の中身は変えない。関所
- サニタイズ — 危険な部分を除去・加工して受け入れる。形をゆがめる副作用があるので、検証で弾けるものは弾くのが優先
- 出力エンコード(出口) — 通した値を、出す先の文脈(HTML・SQL・URL・シェル)に合わせて無害化する。ここが本丸
要点は、検証は「その先どこで使うか」を知らないということ。だから入口でどれだけ厳しく検証しても、出口の無害化を省くと危険になりうる。両者は別concernとして両方やります。
⚠️ 破れ方のパターン
- フロントだけで検証 — 直接サーバへ送られたら素通り。サーバで必ず再検証
- 拒否リスト頼み — 危ないものを列挙する方式は抜けが出る。許可リストへ寄せる
- 正規化忘れ・順序ミス — 検証後に化ける表記ゆれをすり抜けられる
- 検証と無害化の混同 — 入口の検証だけで安心し、出口のエスケープを省く
この部分をもっと深く(上級)
- 注入=混ざること — XSS も SQLインジェクションも、根っこは「データが、出力先の文法で命令として解釈される」こと。HTMLならスクリプトタグ、SQLなら命令の切れ端。つまり危険が生まれるのは出力の瞬間
- 入口検証だけでは閉じない — 入口で形を絞っても、出力先ごとの危険記号まで入口では消しきれない(メールアドレスにも
<は入りうる)。だから根治は出力の文脈に合わせた無害化——XSS なら文脈別エスケープ、SQLインジェクション ならパラメータ化 - 検証は減災、無害化は根治 — 入口の検証は攻撃面を狭める価値があるが、出口の無害化を代替はしない。検証で表面を減らし、出力の文脈で確実に無害化する——この二段構えが要
- 正規化忘れ・順序ミス — 正規化を後回しにすると、検証を通った後で化けてすり抜けられる。正規化しきってから検証する
登場人物メモ:
- ※1 許可リスト — 通してよいものだけを列挙し、それ以外はすべて弾く方式。想定外に強い
- ※2 正規化(canonicalization) — 同じ意味の複数表記を、一意な正規形へ揃える前処理
- ※3 信頼境界 — 信用できる領域とできない領域の境目。検証はこの境界を越える所で行う
やさしく言うと(初級)
- フロントだけで検証 — 直接サーバへ送られたら素通り
- 拒否リスト頼み — 危ないものを列挙する方式は抜けが出る
- 検証と無害化の混同 — 検証(弾く)と、出力時のエスケープ(無害化)は別の対策。両方要る
理解度チェック
そのまま解けます(成績は保存されません)。無料アカウントを作ると、学習の記録と進捗の山登りが始まります。
問1. 入力の「正規化」と「検証」の順序で正しいのは?
問2. 入力検証の「観点」の並べ方として、より安全側なのは?
問3. 検証で「極端に長い入力」を弾くべきだと本文が述べる理由はどれ?
問4. フロント(ブラウザ)側の入力検証の位置づけとして本文が述べるのはどれ?
問5. 入口の「検証」と出口の「出力エスケープ」の関係として正しいのはどれ?
問6. 次のうち「信頼境界の外から来る値」に当たらないのはどれ?
問7. 検証を行う、信用できる領域と信用できない領域の境目を何と呼ぶ?
問8. 全角と半角・大文字と小文字・Unicodeの合成形などの表記ゆれを揃え、検証できる形にそろえる前処理を何と呼ぶ?