ファジングとは?脆弱性を自動検出する仕組みとツール・他テストとの使い分け【2026年版】
ファジング(fuzzing)は、想定外のデータを大量に自動生成してソフトウェアに送り込み、落ちた場所から脆弱性を見つける動的テストです。人手のテストが「正しい入力で正しく動くか」を確かめるのに対し、ファジングは「壊れた入力で壊れないか」だけを機械的に叩き続けます。この記事では、ファジングで見つかるバグと原理的に見つからないバグの境界、ペネトレーションテストや静的解析との使い分け、2026年7月時点で実際に選べるツールの現況を、IPA・LLVM・Go の一次情報にあたって整理します。
まとめ
- ファジングは「クラッシュする欠陥」を見つける手法です。メモリ破壊・未定義動作・無限ループ・パーサの異常終了は得意ですが、認可の抜けや業務ロジックの誤りのように、プログラムが正常終了してしまう脆弱性は原理的に検出できません。
- ペネトレーションテストとは代替関係にありません。ファジングは実装の堅牢性を機械が総当たりで検証し、ペネトレーションテストは侵入可否を人が攻撃者視点で検証します。目的も実施者も違うため、別工程に置きます。
- 導入位置は単体テストの直後が現実的です。入力を受け取る関数(パーサ・デコーダ・プロトコル処理)に絞ってハーネスを書くのが、費用対効果のもっとも高い使い方です。
- 2026年7月時点のOSSの主力は AFL++(v5.02c/2026年6月29日公開)。libFuzzer は原著者が開発を離れ、バグ修正のみのメンテナンス状態だとLLVM公式が明記しています。Go は 1.18 以降、標準ツールチェーンでファジングを書けます。
- コストの中心はツール代ではありません。主要なOSSファザーのライセンス費用は0円で、実費はハーネス実装・シード整備・トリアージの人的工数と、長時間回すマシン時間に集中します。
- 日本語の一次資料は IPA「ファジング活用の手引き」第1版第7刷(2024年8月7日公開)が起点です。IPA が配布していた JPEG テスト支援ツール「iFuzzMaker」は公開停止となり、ツール提供は現在OSSが中心です。
ファジングの定義と、検出できる不具合の境界
ファジングとは、検査対象に「ファズ(fuzz)」と呼ばれる問題を起こしそうなデータ、たとえば極端に長い文字列・境界値・型の違う値・壊れたバイナリを大量に送り込み、対象の挙動を監視して異常を検出する手法です。ファズの生成・送信・監視を自動で行うツールをファザー(fuzzer)と呼びます。
試験で問われる定義(応用情報技術者 平成30年春期 問42)
「ファジングの説明はどれか」という形で情報処理技術者試験に繰り返し出題されており、定義を確認する目的で検索されることも多い用語です。応用情報技術者試験 平成30年春期 午前 問42「ファジングに該当するものはどれか。」の正解は、選択肢ウ「ソフトウェアに,問題を引き起こしそうな多様なデータを入力し,挙動を監視して,脆弱性を見つけ出す。」でした。令和元年秋期 午前 問44 でも同じ論点が問われています。
「異常データの入力」「挙動の監視」「脆弱性の検出」の3点が揃って初めてファジングです。ランダムなデータを投げるだけで監視とクラッシュ入力の保存がなければ、この定義を満たしません。
見つかるバグと、見つからないバグ
ファジングの判定基準は「対象プロセスが異常状態になったか」です。この一点で守備範囲が決まります。
| 検出できる | 検出できない |
|---|---|
| バッファオーバーフロー・境界外読み書き | 認可・権限チェックの抜け |
| ヌルポインタ参照・二重解放・use-after-free | 業務ロジックの計算誤り |
| 符号付き整数のオーバーフローなどの未定義動作 | 設計上の情報漏えい経路 |
| 無限ループ・ハング・過大なメモリ確保 | 正常終了する範囲のSQLインジェクション |
| パーサ・デコーダの異常終了 | 暗号アルゴリズムの選定ミス |
右列に共通するのは「プログラムが正常に終了してしまう」点です。認可漏れは処理系から見れば正しく動作した結果であり、ファザーはこれを異常と判定できません。SQLインジェクションやクロスサイトスクリプティングのようなWebアプリの脆弱性は、レスポンス内容を検査する専用スキャナの領域になります。この領域はOWASP ZAPの診断項目とは?検出できる脆弱性一覧と使い方で扱う動的スキャンの担当で、ファジングとは対象レイヤが違います。
逆に左列は、コードレビューや静的解析では見落としやすい領域です。C/C++/Rust の unsafe ブロック、画像・動画・フォントのデコーダ、独自プロトコルの実装を抱えているなら投資対効果は高くなります。
ファジングの仕組み:入力生成から再現手順の確定まで
ファザーは「入力を作る」「実行する」「異常を検知する」「異常だった入力を保存する」の4つを高速に繰り返します。honggfuzz が永続化モードで「Test APIs directly in-process with iteration speeds up to 1M/sec」と公称するとおり、インプロセス実行なら毎秒数万回から百万回規模で試行できます。これを数時間から数日積み上げるため、実行速度の確保が結果を左右します。
ブラックボックス型とカバレッジガイド型の違い
初期のファザーは、ランダム値や既知の攻撃パターンを機械的に送るブラックボックス型でした。対象の内部を知らずに使える半面、条件分岐の奥の欠陥には届きません。マジックナンバーの一致を要求するパーサでは、ランダム生成がその4バイトを引き当てる確率が事実上ゼロだからです。
現在の主流はカバレッジガイド型です。対象をコンパイル時に計装しておき、実行するたびにどの分岐を通ったかを記録します。新しい経路に到達した入力を「当たり」として保存し、それを変異させて次の入力を作る。この繰り返しで、ファザーは深い分岐へ自力で潜っていきます。AFL++ も libFuzzer も Go の標準機能もこの方式です。内部情報を部分的に使うことからグレーボックスファジングと呼ばれ、ソースコードや設計情報を完全に前提とする方式はホワイトボックスファジングと分類されます。カバレッジの考え方はテストカバレッジとは?C0/C1/C2の網羅率と計測ツール・目標設定を実装者向けに解説と共通しますが、ファジングでは網羅率を目標にせず探索の道しるべとして使います。
「異常」を検知する仕組みとサニタイザの併用
プロセスが落ちなければ異常と判定されない、という性質は取りこぼしを生みます。境界を1バイト超えた読み取りは、多くの場合そのまま動き続けてしまうからです。これを検知可能にするのがサニタイザです。AddressSanitizer(ASan)はメモリの境界外アクセスや use-after-free を即座にクラッシュへ変換し、UndefinedBehaviorSanitizer(UBSan)は符号付き整数のオーバーフローやシフト幅超過といった未定義動作を検知します。
サニタイザを有効にしないファジングは、検出能力を大きく落とした状態で回していることになります。実行速度は2倍から数倍遅くなりますが、見つかる欠陥の数と質が変わるため、ビルドオプションでの有効化を前提に組んでください。
検知したクラッシュはそのままでは使えません。保存された入力は数KBから数MBに膨らんでいることが多く、原因箇所を追えないためです。AFL++ の afl-tmin や libFuzzer の -minimize_crash で最小の再現入力まで削り込んで、初めて開発者に渡せる再現手順が確定します。
ペネトレーションテスト・静的解析・単体テストとの使い分け
ファジングは「ペネトレーションテストの代わりになるのか」「どのテスト工程に入れるのか」が最初の疑問になりやすい手法です。手法名を並べるだけでは選べないので、目的と実施者の軸で整理します。
ペネトレーションテストとの違い
| 観点 | ファジング | ペネトレーションテスト |
|---|---|---|
| 目的 | 実装の堅牢性の検証 | 侵入可否・被害範囲の実証 |
| 対象 | 入力を扱う個々のコンポーネント | システム全体・運用・人 |
| 実施者 | 開発者(自動実行) | 専門技術者(手動主体) |
| 成果物 | クラッシュ再現入力 | 攻撃シナリオと侵入経路の報告 |
| 実施頻度 | CIで継続実行 | リリース前や年次など断続的 |
ファジングが見つけるのは未知のクラッシュ、ペネトレーションテストが示すのは既知の弱点を組み合わせた到達可能性です。クラッシュが実際に悪用可能かは別の検証を要し、その判断基準はexploitとは?脆弱性を悪用する攻撃コードの仕組み・種類・防御を実装者向けに解説で扱う攻撃コードの成立条件と重なります。ファジングで潰した欠陥が攻撃チェーンから1本の経路を消す、という補完関係です。
静的解析との違いと組み合わせ
静的解析はコードを実行せずに欠陥候補を洗い出すため、網羅性が高い代わりに誤検知(false positive)が出ます。ファジングは落ちたものだけを報告するので誤検知はほぼゼロですが、到達できなかったコードには何も言えません。性質が正反対で、片方が他方を代替できません。両手法の詳しい比較は静的解析と動的テストの違いとは|検出できるバグ・代表ツール・使い分けを比較にまとめています。
実務では、静的解析で疑わしい箇所を特定し、その関数をファジングの対象として優先的にハーネス化する順序が効率的です。静的解析そのものをこれから導入する場合は静的解析とは何か?ソースコードを実行せずに品質を確保する手法から始めてください。
単体テスト・結合テストのどこに差し込むか
ファジングは単体テストの延長線上に置くのがもっとも扱いやすい配置です。単体テストが「この入力ならこの出力」を検証するのに対し、ファジングは同じ関数に「どんな入力でも落ちない」を求めます。関数が切り出されていればハーネスは数十行で済みます。結合テスト以降にシステム全体へかける方法もありますが、実行速度が落ち原因箇所の特定に手間がかかるため、工程が後ろになるほど費用対効果は下がります。
- 単体テスト直後:パーサ・デコーダ・シリアライザなど入力を解釈する関数にハーネスを書く。ここが本命。
- CIへの組み込み:プルリクエストごとに数分だけ回し、既知のクラッシュ入力を回帰テストとして常時実行する。
- 結合テスト以降:ネットワークプロトコルや実機ファームウェアなど、単体では切り出せない対象に限定する。
- リリース前のセキュリティ診断:ファジングの結果は診断の入力材料として渡し、診断そのものはペネトレーションテストや脆弱性診断に任せる。
ファジングツールの現在地(2026年7月時点)
この分野は開発体制の変化が速く、ツール名の列挙だけでは選べません。2026年7月時点の状況を一次情報で確認した結果を整理します。
OSSファザーの選択肢と現況
| ツール | 主な対象 | 2026年7月時点の状況 |
|---|---|---|
| AFL++ | C/C++/バイナリ | v5.02c(2026年6月29日公開) |
| libFuzzer | C/C++(インプロセス) | バグ修正のみ/原著者はCentipedeへ移行 |
| Go標準(testing.F) | Go | Go 1.18以降、標準ツールチェーンに同梱 |
| cargo-fuzz | Rust | 0.13.2(2026年6月9日公開) |
| Jazzer | Java/JVM言語 | v0.30.0(2026年2月24日公開) |
| Atheris | Python | 3.1.0(PyPI公開版) |
| honggfuzz | C/C++ | Googleのリポジトリで公開/公式製品ではない |
注意すべきはlibFuzzerです。LLVM公式ドキュメントには「The original authors of libFuzzer have stopped active work on it and switched to working on another fuzzing engine, Centipede. LibFuzzer is still fully supported in that important bugs will get fixed. However, please do not expect major new features or code reviews, other than for bug fixes.」と明記されています。使えなくなるわけではないものの、新機能を期待して新規に選ぶ対象ではありません。C/C++ で新しく始めるなら AFL++ を第一候補にし、libFuzzer は cargo-fuzz や Atheris のバックエンドとして間接的に使う位置づけが妥当です。なお honggfuzz は github.com/google/honggfuzz で公開されていますが、README には「This is NOT an official Google product」と明記されています。
Go は導入障壁がもっとも低い部類です。公式のセキュリティドキュメントに「Go supports fuzzing in its standard toolchain beginning in Go 1.18.」とあり、追加のツールなしで書けます。公式チュートリアルのとおり関数名を FuzzXxx にし、引数を *testing.T ではなく *testing.F にするだけです。次は書き方を示す擬似コードで、ParseConfig は各プロジェクトの実装に読み替えてください。
func FuzzParseConfig(f *testing.F) {
f.Add("key=value") // シードコーパスを与える
f.Fuzz(func(t *testing.T, s string) {
cfg, err := ParseConfig(s)
if err != nil {
return // パースエラーは想定内なので異常ではない
}
if _, err := ParseConfig(cfg.String()); err != nil {
t.Errorf("round trip failed: %q", s)
}
})
}
実行は go test -fuzz=FuzzParseConfig です。失敗した入力は testdata 配下に自動保存され、以降は通常の go test でも回帰テストとして実行されます。ただし公式チュートリアルが「Go fuzzing with coverage instrumentation is only available on AMD64 and ARM64 architectures currently」と注記しているとおり、カバレッジ計装が効くアーキテクチャは限定されます。
導入の4ステップ
ツールを決めたあとの進め方は、対象を問わず次の順序になります。
- 対象の選定:外部入力を最初に解釈する関数を洗い出し、パーサ・デコーダから着手する。
- ハーネスの実装:バイト列を対象関数の引数へ変換する数十行を書く。ここの設計が検出力を決める。
- シードコーパスの投入:実際に流通している正常データを初期入力として与え、深い分岐への到達を早める。
- クラッシュのトリアージ:検出結果を最小化・重複排除し、外部から到達できるものを優先して修正へ回す。
継続実行の基盤:OSS-FuzzとClusterFuzzLite
ファジングは回し続けて初めて効果が出ます。Google の OSS-Fuzz はオープンソース向けに継続実行を無償提供しており、README には「As of May 2025, OSS-Fuzz has helped identify and fix over 13,000 vulnerabilities and 50,000 bugs across 1,000 projects.」と記載されています。1,000プロジェクトで13,000件以上という規模が、継続実行の効果を端的に示す数字です。
自社の非公開プロダクトは対象外ですが、同じ仕組みを CI に持ち込む ClusterFuzzLite が「ClusterFuzzLite is a continuous fuzzing solution that runs as part of Continuous Integration (CI) workflows」として公開されています。プルリクエスト単位で短時間だけ回し、マージ前にクラッシュを止める使い方が想定されています。
IPAが公開している日本語資料の状況
日本語で手順まで踏み込んだ資料は、IPA の「ファジング活用の手引き」が実質的な標準です。IPAの更新履歴によれば第1版第7刷が2024年8月7日に公開されており、「製品出荷前に未知の脆弱性をみつけよう」の副題どおり開発ライフサイクルへの組み込みを狙った資料です。AFL 系ツールの具体的な手順は、2020年3月27日公開の別冊「ファジング実践資料(AFL編)」で補えます。
注意が必要なのは JPEG テスト支援ツール「iFuzzMaker」です。IPAの更新履歴では2023年8月9日付で公開停止と記載されており、古い解説記事がいまだ推奨ツールとして挙げていても現在は入手できません。IPA の資料で考え方を学びツールは OSS を使う、というのが2026年時点の現実的な進め方です。
費用構造:無料ツールでも無料にならない部分
「ファジングツールのコスト」を調べる場合、ライセンス費用だけを見ると判断を誤ります。上の表に挙げたOSSファザーはすべてライセンス費用が0円で、費用の大半は別のところに発生するからです。
- ハーネス実装の工数:対象関数ごとに入力を受け渡すコードを書きます。成否をもっとも強く左右する部分で、切り出し方次第で検出力が数倍変わります。
- マシン時間:クラウドで専用インスタンスを常時稼働させれば、その従量課金がそのまま実費です。CIで数分回す運用と専用マシンで数日回す運用ではコストが桁で違います。
- トリアージ工数:クラッシュの重複排除と脆弱性判断は自動化しきれません。数百件が同一原因ということも珍しくありません。
- 商用ツール・受託サービス:組込み機器やプロトコル試験に強い商用製品や検証サービスは、公開価格を掲示せず個別見積もりが前提です。対象機器の種類とプロトコル数で金額が変わるため、比較する際は台数と対象プロトコルを揃えて見積もりを取ってください。
ファジングを採用すべきでない対象と条件
ファジングは万能ではなく、費やした工数が回収できない対象があります。導入判断で外すべき条件を先に挙げます。
1実行あたりのコストが高い対象には向きません。数万回から数百万回の試行が前提のため、1回の実行に数秒かかる対象では探索が進まないからです。GUI操作を伴うアプリケーション、起動の遅いサーバー全体、実機デバイスへのシリアル通信が該当します。関数レベルに切り出してハーネス化するか、別の手法を選んでください。
入力の受理条件が厳しい対象も、そのままでは効果が出ません。チェックサムや電子署名を最初に検証する実装では、変異させた入力が検証段階で全て弾かれるためです。テストビルドで検証処理を無効化するのが定石ですが、本番と異なるバイナリを検査していることになるので無効化した範囲は記録してください。多段の認証やセッション確立を要求するプロトコルも、状態遷移を再現するハーネスを書かない限り入口で止まります。
メモリ安全な言語で書かれた業務ロジック中心のコードは、優先度を下げて構いません。Java や Go、Rust の safe な範囲では、C/C++ で問題になるメモリ破壊が言語機構で防がれています。パニックや例外による可用性の問題は検出できるものの、投資対効果はネイティブコードのパーサに比べて明確に落ちるでしょう。
逆に、外部から来たバイト列を自前のコードで解釈している箇所は言語や規模を問わず優先対象です。ファイルフォーマットのデコーダ、独自プロトコルの受信処理、圧縮・暗号ライブラリのラッパーが、もっとも欠陥の出やすい場所になります。
よくある質問
ファジングとファズテスト(fuzz testing)は違うものですか?
同じ手法を指します。英語では手法そのものを fuzzing、テスト工程としての実施を fuzz testing と呼び分けることがありますが、日本語ではどちらも「ファジング」と訳されます。起源はウィスコンシン大学の Barton Miller が1988年秋の大学院講義 CS736 で出した課題で、成果は論文「An Empirical Study of the Reliability of UNIX Utilities」(B.P. Miller, L. Fredriksen, B. So/Communications of the ACM 33巻12号・1990年12月)にまとめられています。
ファジングとサニタイザ(ASan/UBSan)は併用が必要ですか?
C/C++ を対象にするなら併用が前提です。詳細は本文のサニタイザの節に書いたとおりで、有効化しないとプロセスが落ちない不具合が検出対象から漏れます。Go や Rust の safe な範囲では、ランタイムが同等の検知を担うため個別のサニタイザ設定は不要です。
OSS-Fuzz は自社の非公開製品にも使えますか?
使えません。OSS-Fuzz はオープンソースプロジェクト向けのサービスです。非公開プロダクトでは ClusterFuzzLite を自社CIで運用するか、商用サービスを利用します。なお採択条件は公式に「must have a significant user base and/or be critical to the global IT infrastructure.」と記されており、公開していれば自動的に対象になるわけでもありません。
ファジングは何時間くらい回せば十分ですか?
時間ではなくカバレッジの伸びで判断してください。カバレッジガイド型のファザーは、新しい実行経路を見つけるたびにコーパスを増やします。一定時間まったく新しい経路が見つからない状態が続いたら、そのハーネスでの探索は頭打ちです。時間を延ばすよりも、シードコーパスに実際の入力データを追加する、対象関数を分割してハーネスを増やすといった手を打つほうが成果が出ます。CI で回す短時間実行と、専用環境での長時間実行を分けて運用するのが実務的です。
ファジングで検出されたクラッシュはすべて脆弱性として扱うべきですか?
いいえ。攻撃に使えない単なる異常終了や、ハーネスの不備によるクラッシュも混ざります。判断の目安は「その入力が外部から与えられうるか」と「クラッシュ時にメモリの書き換えが起きているか」の2点です。外部入力で到達でき書き込み系のメモリ破壊を伴うものは優先度が高く、内部からしか呼ばれない関数のアサーション失敗は品質バグとして扱えば足ります。深刻度の付け方やCVE・CVSSでの評価手順は脆弱性とは?種類・CVE/CVSSの仕組みと発見から修正までの実務を解説を参照してください。