ヌルバイト攻撃は、入力データにヌル文字(0x00)を含め、文字列処理やコンポーネント間の解釈差を利用して検証や制御をすり抜ける攻撃手法です。特に、ファイル名、パス、拡張子判定、外部ライブラリ連携など、入力値を複数の処理系で扱う実装では注意が必要です。対策では、入力直後の正規化、制御文字の拒否、入力値をファイル名やパスに直結させない設計、境界条件テストを組み合わせます。
ヌルバイト攻撃とは、入力データにヌルバイト(0x00)を含めることで、文字列の扱いに関する不備を突き、アプリケーションの動作を意図的に変える攻撃手法です。C言語系の文字列処理や一部のライブラリでは、ヌル文字が文字列の終端として扱われることがあり、検証時と実処理時で解釈が変わると、入力チェックの回避につながります。
ヌル文字は、それ自体が常に危険な文字というより、複数の処理系で異なる意味を持ち得る点が問題になります。アプリケーション側では「example.php%00.jpg」のような入力全体を見ていても、下流の処理ではヌル文字以降が無視され、「example.php」として扱われる場合があります。この差が、拡張子チェック、パス検証、ログ記録などの不一致を生みます。
入力値をアプリケーションで検証したあと、別の言語、ライブラリ、OS API、外部コンポーネントに渡す構造では、ヌル文字の扱いが変わる場合があります。検証処理では許可された文字列が、実処理では短縮された文字列や別の値として扱われると、攻撃が成立します。
ファイルアップロード、ログ出力、URLやパスの生成、拡張子判定など、文字列処理に依存する箇所は影響を受けやすい領域です。特に、末尾の拡張子だけでファイル種別を判断する実装、禁止文字を削除するだけの処理、入力値を保存名にそのまま使う処理は見直しが必要です。
現在の主要な言語やフレームワークでは、ヌルバイトを含む入力を明示的に拒否したり、エラーとして扱ったりする実装が増えています。それでも、古いライブラリ、互換性維持のための処理、独自実装の入力処理が残っている場合は、ヌル文字による解釈差が残る可能性があります。
入力を受け取った直後に、文字コード、エンコーディング、制御文字の扱いを正規化し、その後にバリデーションを行います。正規化前の文字列を検証したり、検証後に別形式へ変換したりすると、検証時と実処理時の値が一致しない可能性があります。入力処理は、できるだけ一貫した場所で完了させます。
利用者が入力する通常のフォーム、ファイル名、検索条件、識別子などで制御文字が不要な場合は、ヌル文字を含む入力をサーバー側で拒否します。クライアント側の入力制限だけでは不十分です。API、管理画面、バッチ連携など、入力経路ごとに同じ基準で拒否できるようにします。
アップロードファイル名やパス要素を、保存名や参照名にそのまま使わない設計にします。保存時はサーバー側で生成したIDを使い、利用者向けの表示名は別項目として管理します。パスを組み立てる場合も、許可済みのディレクトリやファイル識別子だけを使い、入力値から直接ファイルパスを作らないようにします。
ヌル文字、制御文字、異常に長い文字列、エンコーディング混在、パス区切り文字、拡張子偽装などをテストケースに含めます。ファイルアップロード、パス生成、外部ライブラリ連携、ログ出力など、文字列の解釈が切り替わる境界を重点的に確認します。CIに組み込むことで、修正後の再発も検出しやすくなります。
WAFやIDSで、ヌルバイトを含むリクエストを検知できる場合があります。ただし、アプリケーション側に解釈差が残っている限り、根本的な解決にはなりません。WAFやIDSは補助的な防御として扱い、入力処理とファイル処理の修正を優先します。
ログに入力値をそのまま記録すると、ヌル文字以降が表示されない、検索できない、監視ツール上で別の値に見えるといった問題が起こる場合があります。制御文字はエスケープし、必要に応じて16進表現を併記します。攻撃調査では、画面上の見え方ではなく、実際に受け取ったバイト列を確認できることが重要です。
ヌルバイト攻撃は単独の攻撃というより、入力値の解釈差を利用して別の脆弱性を成立させる手段として現れることがあります。代表的には、ディレクトリトラバーサル、ファイルインクルード、拡張子チェック回避、ログ改ざんの補助などです。対策では、「ヌル文字だけを消す」のではなく、入力値をどの処理系へ渡し、どの形式で扱うのかを確認する必要があります。
ヌルバイト攻撃の本質は、ヌル文字そのものではなく、入力検証と実処理の間で起きる解釈差にあります。ファイル名、パス、拡張子、外部ライブラリ連携など、文字列の意味が切り替わる箇所では、入力直後の正規化、制御文字の拒否、入力値を直結しない設計、境界条件テストを組み合わせて確認します。WAFやIDSは補助策として位置付け、アプリケーション側の入力処理を優先して修正することが対策の中心です。
A.入力検証と下流処理で文字列の解釈が異なり、検証時に許可された値が実処理では別の値として扱われる場合に成立します。
A.必ず終端になるわけではありません。言語、ライブラリ、OS API、外部コンポーネントによって扱いが異なるため、実装ごとの確認が必要です。
A.注意が必要です。拡張子判定、保存名生成、パス作成に入力値をそのまま使うと、検証回避や想定外のファイル処理につながる可能性があります。
A.十分ではありません。削除後に別の意味を持つ文字列へ変わる場合があります。不要な制御文字は拒否し、正規化後の値を検証する設計が必要です。
A.入力直後に正規化とバリデーションを行い、制御文字を拒否し、ファイル名やパスに入力値を直結させないことです。
A.一部のリクエストは検知または遮断できる場合があります。ただし、アプリケーション側の解釈差が残っている場合は、実装の修正が必要です。
A.制御文字をエスケープし、必要に応じて16進表現を併記します。調査時に、実際に受け取った値を確認できる形式にします。
A.古い実装、独自の入力処理、外部コンポーネント連携が残っている環境では問題になる場合があります。更新と境界条件テストで確認します。
A.入力処理、拡張子判定、パス検証、ファイル保存、外部ライブラリやOS APIへ値を渡す箇所を優先して確認します。
A.ヌル文字、制御文字、異常長、エンコーディング混在、拡張子偽装、パス区切り文字を含む入力を境界条件テストとして用意します。