第1章 総論
開発工程と脆弱性対策
脆弱性対策をどの工程で行うか
脆弱性対策をどの工程で行うかということは重要なことである。例えば、ソースコードが書かれた後でそれを検査するというやり方でも一定の効果が得られるが、ソースコード中に脆弱性を見つけたときにはすでに数多くのものが存在していて、対処に多くの時間とコストがかかり過ぎるおそれがある。
このコンテンツで提案したいのは、より予防的なコーディングをしようというものである。
脆弱性を減らすためのコーディングスタイルや、設計における考慮事項を開発プロジェクトが持ち、そのパターンから外れているものを「問題として認識し是正する」活動を行うことによって、最終的に作られるソフトウェアにおける脆弱性の発生を低く抑えるというものである。
従来型の開発プロジェクトの問題
従来型の開発プロジェクトにおいて脆弱性が見つけ出されるのは、プログラムのコードが書かれ、リリースする前のテストの段階であることがしばしばである。この段階での脆弱性が見つけ出され、修正される。ところが、その際の脆弱性の除去は十分でなく、リリース後の運用時に脆弱性の存在が次々と露見してゆく。
脆弱性を十分低減できないことの要因としては、大きくふたつがある。
その1は、脆弱性への対処を下流の工程で初めて行っているというものである。上流工程で問題を見つける工夫をしていないため、脆弱性発生の要因が隠れて存在していて、製品が形をなすにつれ多くの脆弱性が製品の中に入り込む。
その2は、脆弱性への対処が不十分なまま製品がリリースされがちだということである。工程の下流で脆弱性を見つけて修正する場合、ひとつ問題が見つかったときの修正コストが工程の下流になればなるほど増大。開発プロジェクトのリソースを十分投入できず、あらゆる問題を解消できないまま製品のリリース日を迎えるといった状況も世の中には存在している。
このコンテンツが提案する開発形態
このコンテンツが提案するモデルは、ソフトウェア開発工程の上流の段階から、脆弱性の要因の除去につとめるものである。現実問題としてすべての問題を除去しきることは困難であるが、のちに大きな問題に発展しそうな脆弱性の芽を小さなうちに摘んでおくことには大きな効果がある。
上流工程で脆弱性の要因を見つけ出して対処することにより、全体として下流工程に現れる脆弱性の数を少なく抑えることを狙う。
脆弱性を生みにくい設計や実装のありかたについての知識を収集し、活用することによって実現する。本コンテンツはこうした知識を集めたものである。
実際には問題をすべてつぶすことはできず、問題が潜在したまま下流工程に送られるものもあり得る。そうしたもののいくつかはテスト工程でも見逃され、リリース後の製品の中で脆弱性が見つかるといったことは皆無とはいえない。
それでも、上流から脆弱性の要因をつぶす工夫をすることによって、脆弱性をより少ないものに抑えるという効果が期待できる。
また、脆弱性の要因に早めに対処するにあたり、各工程でツールを活用することも、脆弱性要因の検出と対策に関する生産性・網羅性・精度の向上に寄与する。
このコンテンツの脆弱性対策アーティクル
このコンテンツでは、C言語、C++言語を中心としたプログラミングに関する脆弱性対策論点として約40のアーティクルを記述している。これらのアーティクルは次の10のカテゴリに分かれている。
- 総論
- 脆弱性回避策とソフトウェア開発工程
- 計画されたセキュリティ機能
- 不測の事態対策
- プログラム配置対策
- フェイルセーフ
- データ漏えい対策
- 入力検査
- ファイル対策
- 著名な脆弱性対策
工程の広がり
それぞれの論点はあるひとつの開発工程にのみ関連するものではなく、要件定義、設計、実装、テストという工程の流れ──これは必ずしも時間の流れではなく、抽象から具象への流れである──に沿って広がっている。
論点はどれかの上流の工程との関わりから始まり、実装、テストといった下流の工程にどれもが流れ込んでいる。
例えば、アクセス制御や、セッション管理等の論点は、対象のソフトウェアがどのようなセキュリティ対策機能をもつべきかを要件定義の段階から考慮しておく必要があり、「要件定義」から「実装」まで関連する工程の広がりが大きい。その一方で、フォーマット文字列攻撃対策の場合、これは「実装」の段階で実施すれば一定の効果が期待できるものであり、工程の広がりは比較的小さい。
開発の現場においてはさまざまな形態があり得るが、本コンテンツではソフトウェアの開発工程を大まかに次のように想定している。
- 要件定義──対象のソフトウェアがどうあらねばならないかを決める工程
- 設計──目標のソフトウェアをどのように組み立てるかを決める工程
- 実装──実際にソフトウェアのコードを書き、単体テストを行う工程
- テストおよび統合──ソフトウェアの各部分をテストしつつひとつのシステムに組上げる工程
- 運用──ソフトウェアの実際の使用
アーティクルと工程
このコンテンツの各アーティクルと開発工程との関連は次の図のようなものである。

これらの関連を工程別に記すと、次のようになる。
(1) 要件定義の段階から考慮するのがよいと考えられるもの
- a. 総論
- C/C++がもたらす問題
- 既存ソフトウェアの脆弱性分析
- 開発工程と脆弱性対策
- b. 脆弱性回避策とソフトウェア開発工程
- 脅威モデリング
- c. 計画されたセキュリティ機能
- アクセス制御: #1 本人認証
- アクセス制御: #2 アクセス認可
- 破られにくい暗号技術と擬似乱数の使用
- d. 不測の事態対策
- ログ記録による証跡確保とログ自体の漏えい対策
- サービス不能状態対策
(2) 設計の段階から考慮するのがよいと考えられるもの
- a. 総論
- ツールの利用
- b. 脆弱性回避策とソフトウェア開発工程
- セキュリティテスト
- d. 不測の事態対策
- メモリリーク対策
- レースコンディションの一般的対策
- e. プログラム配置対策
- 構成ファイルからの情報漏えい対策
- 子プロセスからの侵害対策
- chroot, jailの利用
- f. フェイルセーフ
- セキュアなデフォルト
- 体系だてたエラーハンドリング
- g. データ漏えい対策
- 最小の特権
- 最小のアクセスパーミッション
- テンポラリファイル(Unixの一時ファイル)
- コマンドラインからの情報漏えい対策
- 親切すぎるエラーメッセージの回避
- h. 入力検査
- 入力検査の概要
- 受信ファイルの検査
- 環境変数の検査とリセット
(3) 実装の段階で初めて考慮してもあまり手遅れではないと考えられるもの
- b. 脆弱性回避策とソフトウェア開発工程
- ソースコードレビュー
- g. データ漏えい対策
- メモリクリア失敗対策
- ページングおよびメモリダンプ対策
- i. ファイル対策
- ファイルの別名検査
- シンボリックリンク攻撃対策
- ファイルレースコンディション対策
- ファイル拡張子による起動対策
- j. 著名な脆弱性対策
- バッファオーバーフロー: #1 概要
- バッファオーバーフロー: #2 コード記述時の対策
- バッファオーバーフロー: #3 ソースコードの静的検査
- バッファオーバーフロー: #4 あふれを検出するデバッグ
- バッファオーバーフロー: #5 運用環境における防御
- フォーマット文字列攻撃対策
- 整数オーバーフロー攻撃対策
- SQL注入(SQLインジェクション)攻撃対策
- コマンド注入(コマンドインジェクション)攻撃対策