信頼性が高くセキュリティで保護された C++ プログラムを構築する

米国政府の出版物 NISTIR 8397: ソフトウェアの開発者検証のための最小基準に関するガイドラインには、任意のプログラミング言語で信頼性の高い安全なソフトウェアを構築する方法に関する優れたガイダンスが含まれています。

このドキュメントは、NISTIR 8397 と同じ構造に従います。 各セクション:

  • は、C++ やその他の言語用の Microsoft 開発者向け製品を使用して、そのセクションのセキュリティ ニーズを満たす方法をまとめたものです。
  • は、各領域で最大限の価値を得るためのガイダンスを提供します。

2.1 脅威モデリング

まとめ

脅威モデリングは、特に開発ニーズに合わせてスケーリングし、ノイズを軽減する方法で適用される場合に、貴重なプロセスです。

Recommendations (推奨事項)

脅威モデリングは、動的なセキュリティ開発ライフサイクル (SDL) の一部である必要があります。 製品全体、特定の機能、または大規模な設計または実装の変更については、次の点をお勧めします。

  • 堅牢で動的な SDL を使用して、開発者チームとの早期エンゲージメントとアプローチの権利化を可能にします。
  • ターゲットを絞った方法で脅威モデリングを適用します。 すべての機能に脅威モデリングを適用しますが、公開されている、複雑な、または重要な機能から戦術的に開始します。 トップダウン製品レビューの一環として、定期的に適用してください。
  • 設計を変更する機会が残っている場合は、(すべてのセキュリティ要件と同様に) 脅威モデリングを早期に適用します。 また、脅威モデルは、攻撃面の縮小やセキュリティのための設計など、他のプロセスへの入力として機能します。 後で作成される脅威モデルは、ペン テスト (侵入テスト) またはファジーなどのセキュリティ テストが必要な領域に最適な "アンケート" です。 ベースライン脅威モデルを作成した後は、攻撃面の変化に応じてそれを繰り返し実行することを計画します。
  • 資産インベントリとコンプライアンスを使用して、製品を構成するものを適切に追跡し、セキュリティアーティファクト (脅威モデルを含む) とそれらが適用される資産を追跡します。 このアプローチにより、リスクの自動評価が向上し、変更される特定のコンポーネントまたは機能にセキュリティの取り組みに集中できます。
  • Azure では、Microsoft Threat Modeling Tool は 2022 年に Azure 開発用に更新されました。 詳細については、「Microsoft Threat Modeling Tool の概要 - Azure」を参照してください

サポート要素とプラクティス

脅威モデリングを適切に適用し、過度の使用や過度の使用を回避するには、最初に次の主要な概念に対処する必要があることがわかりました。

開発アプローチ

まず、チームの開発アプローチを理解します。 アジャイル開発ワークフローを使用して数十の変更を毎日運用環境にプッシュするチームの場合、すべての機能変更に対して脅威モデルの更新を要求することは現実的または合理的ではありません。 代わりに、機能の機能要件を記述するときに最初から、セキュリティ要件のアンケートを含める方法を検討してください。 アンケートでは、機能に関する特定の質問に焦点を当てて、SDL の将来の側面が適用されるかどうかを判断する必要があります。 次に例を示します。

  • この機能は、マルチテナント環境で顧客分離を提供する方法の設計に大きな変更を加えますか? その場合は、完全な脅威モデルを実行することを検討してください。
  • 新しい機能ではファイルのアップロードが許可されますか? その場合、おそらくより適切なのは、Web アプリケーションのセキュリティ評価です。
  • この変更は、主に機能 UI の変更にすぎませんか? その場合は、従来の自動ツール以外に何も必要ありません。

セキュリティ アンケートの結果は、どの SDL 手法をどの開発ユニットに結び付けるかを通知します。 また、機能の SDL タイムラインについて開発パートナーに通知するため、適切な時間に共同作業を行うことができます。

製品在庫

第 2 に、メイン評価を任されている製品の強力な資産インベントリを維持します。 製品は複雑に成長しています。 接続されているデバイス用のソフトウェアを記述するのが一般的です。

  • センサー (旅客鉄道や車両など)
  • バスベースのネットワークで、車両内の他のコンポーネント (CANBUS や PROFIBUS など) と通信します。
  • お客様のデバイスやクラウドバックエンドとの通信のためのワイヤレス/携帯電話/Bluetooth、
  • デバイスまたはフリート管理アプリケーションにフィードバックするクラウド内の機械学習
  • その他にも用途はあります。

このような複雑な製品では、脅威モデリングが重要です。 強力な資産インベントリを使用すると、製品スタック全体を表示して全体像を確認したり、新機能や変更された機能が製品のセキュリティに与える影響を評価する必要がある重要な場所を確認したりできます。

粒度と統合

明確なメトリックを使用してコンプライアンスを測定するシステムを確立します。

  • 機能レベルの開発のコンプライアンスを定期的に測定します。 一般に、機能のコンプライアンスは、開発者のシステムやコードのコミット/マージ時であっても、頻度が高く、粒度が小さい場合に測定する必要があります。
  • 機能またはコンポーネントが使用されている広範な製品のセキュリティを定期的に評価します。 通常、より広範な評価は、モジュールやシステムのテスト時など、頻度が低く、粒度が広く行われます。

スケール

セキュリティ成果物と脅威モデル レビューの出力をキャプチャして保持する適切な資産インベントリ システムを保持します。 明確なインベントリを使用すると、パターンのレビュー出力を評価し、製品セキュリティ プログラムを定期的に調整する方法についてインテリジェントな決定を行うことができます。

要件フェーズのセキュリティ アンケート、脅威モデリングの結果、セキュリティ評価の結果、自動化されたツールからの結果を組み合わせてみてください。 これらを組み合わせることで、特定の製品の相対的なリスクの観点 (理想的には "ダッシュボード") を自動化して、脅威モデリングから最適な価値を得るために何に集中すべきかをセキュリティ チームに通知することができます。

2.2 自動テスト

まとめ

自動テストは、コードの品質と安全性を確保するための重要な方法です。 これらは、脅威モデリングなど、このドキュメントでメンション他の領域をサポートする際に不可欠な要素です。 他のセキュリティで保護されたコーディングプラクティスと組み合わせて使用すると、コードベースに導入されるバグや脆弱性から保護するのに役立ちます。

キーの属性

テストは、信頼性が高く、一貫性があり、分離されている必要があります。 これらのテストでは、可能な限り多くのコードをカバーする必要があります。 すべての新機能とバグ修正には、可能な限りコードの長期的なセキュリティと信頼性を確保するための対応するテストが必要です。 自動テストを可能な限り多くの環境で定期的に実行し、実行され、すべての領域をカバーしていることを確認します。

  • 最初に実行する必要がある場所は、変更を加えているコンピューター上にあります。 テストの実行は、編集に使用されている IDE 内で、または開発者が変更を行う際にコマンド ライン上のスクリプトとして最も簡単に実行できます。
  • 次に実行する必要がある場所は、pull request のコミット/マージ プロセスの一部です。
  • テストを最後に実行する場所は、継続的インテグレーションおよび継続的配置 (CI/CD) パイプラインの一部として、またはリリース候補のビルド上にあります。

テストの範囲は各ステップで増加する必要があります。最後の手順では、他の手順で見逃す可能性があるすべての対象範囲が提供されます。

継続的な使用とメインテナント

テストの信頼性は、メインテスト スイートの有効性を維持する上で重要な部分です。 テストの失敗を割り当てて調査する必要があります。潜在的なセキュリティの問題は優先度が高く、プロンプトと事前に決められた時間内に更新されます。 テストの失敗を無視することは一般的な方法ではありませんが、厳密な正当な理由と承認が必要です。 テスト スイート自体の問題によるテストエラーは、製品の問題が見逃される可能性があるカバレッジの失効を防ぐために、他のエラーと同じように扱う必要があります。

テストの種類(特に単体テスト)

自動テストにはいくつかの種類があり、すべてのアプリケーションに適用できるわけではありませんが、適切なテスト スイートにはさまざまな種類の選択が含まれています。 単体テストなどのコード ベースのテスト ケースは最も一般的であり、最も不可欠であり、すべてのアプリケーションに適用され、修正のためにできるだけ多くのコード パスを意図的にカバーします。 これらのテストは小さく、迅速であり、マシンの状態に影響を与えないため、テストの完全なスイートを迅速かつ頻繁に実行できるようにする必要があります。 可能であれば、ハードウェアのセットアップが異なる多数のコンピューターでテストを実行し、1 つの種類のコンピューターでは再現できない問題をキャッチします。

Visual Studio

Visual Studio Test エクスプローラーは、最も一般的な C++ テスト フレームワークの多くをネイティブでサポートしており、その他のフレームワーク用の拡張機能をインストールするオプションもあります。 この柔軟性は、作業中のコードをカバーするテストのサブセットを実行する場合に役立ち、発生したテストエラーを簡単にデバッグできます。 また、Visual Studio を使用すると、既存のプロジェクト用に新しいテスト スイートを簡単に設定でき、CodeLens などの便利なツールを使用してこれらのテストを簡単に管理できます。 Visual Studio を使用した C/C++ テストの記述、実行、および管理の詳細については、「C/C++ の単体テストの記述 - Visual Studio (Windows)」を参照してください

Azure と GitHub CI/CD で

静的分析、コンポーネント検出など、より詳細な検証を行い、実行に時間がかかるテストは、プル要求テストや継続的インテグレーション テストに適しています。 Azure DevOps と GitHub Actions を使用すると、検証を自動的に実行し、検証が失敗した場合チェックコードをブロックできます。 自動化された適用により、チェックされているすべてのコードが、実行されているこれらのより厳格なチェックに基づいてセキュリティで保護されます。 Azure Pipelines と Azure DevOps Build Validation について説明します。

2.3 コードベースまたは静的分析

概要 静的コード/バイナリ分析は、既定でセキュリティで保護するために、既定で有効にする必要があります。 静的分析は、お客様のコンピューターで悪用が発生する可能性がある実行時ではなく、構築時に必要な安全ポリシーとセキュリティ ポリシーについてプログラムを分析します。 静的分析では、ソース コード形式またはコンパイル済みの実行可能ファイル形式でプログラムを分析できます。

おすすめ Microsoft では、次のことをお勧めします。

  • 入力ソース コード (コンパイル前) と実行可能バイナリ (コンパイル後) の両方について、すべての C++ プログラムに対して静的分析を有効にします。 "有効にする" とは、開発者のコンピューター上の各ビルド中に分析を実行すること、または後でコードを検査するための個別のビルドとして、またはチェック要件として実行することを意味する場合があります。
  • テストの一形態として CI パイプラインに静的分析を組み込みます。
  • 定義による静的分析には誤検知が付属しており、その事実を品質フィードバック ループに組み込む準備が整います。 すべての低誤検知の警告をすばやく有効にします。 その後、徐々に高い誤検知を犠牲にして重要なバグにフラグを付けるルールを定期的に追加するため、コード ベースが警告クリーンをコンパイルするルールの数を徐々に増やすように積極的に取り組みます (最初は、それらのルールに対してコード ベースがクリーンされる前)。
  • 常にサポートされている最新バージョンの Visual Studio を使用し、最新のパッチ リリースが使用可能になるとすぐに使用できるようにエンジニアリング環境を設定します。次の開発ステージ/サイクルに遅れはありません。

主なツール は、次の点に注意して使用してください。

注:

  • /analyze を使用すると、コンパイル時に C++ コードを静的に分析して、重要なセキュリティと信頼性のコードの脆弱性を特定できます。 これは、C++ プログラムの開発タイムライン全体で有効にする必要があります。 まず、最小ベースラインとして少なくとも既定で "Microsoft Native Recommended" を有効にします。 次に、エンジニアリング ポリシーで必要に応じて、さらに多くの規則 (特に C++ コア ガイドライン規則) を指定する方法については、ドキュメントを参照してください。 ソース コードの静的分析機能は、Visual C++ IDE とコマンド ライン ビルド ツールの両方で使用できます。
  • /W4可能/WXな限り有効にする必要があります。コードを高い警告レベル (W4) でクリーンコンパイルし、警告を修正する必要があるエラー (WX) として扱うようにします。 これらのオプションを使用すると、他の静的分析ツールではチェックできない初期化されていないデータ エラーを検出できます。エラーは、コンパイラ バックエンドが相互分析とインライン化を実行した後にのみ表示されるためです。
  • BinSkim バイナリ分析により、プロジェクトでさまざまなセキュリティ機能が有効になります。 BinSkim は PDB やその他の出力を生成します。この出力により、チェーンオブカストディの検証とセキュリティの問題への効率的な対応が容易になります。 プログラムで生成または使用されるすべての実行可能バイナリ (.sysまたは.exe) を分析するには、 .dll BinSkim ツールを実行することをお勧めします。 BinSkim ユーザー ガイドには、サポートされているセキュリティ標準の一覧が含まれています。 Microsoft では、BinSkim ツールによって "エラー" として報告されたすべての問題を修正することをお勧めします。 "警告" として報告された問題は、問題を解決するとパフォーマンスに影響を与えたり、必要ではない可能性があるため、選択的に評価する必要があります。

Azure および GitHub CI/CD では、Microsoft では、リリース CI/CD シナリオでソース コードとバイナリ静的分析を常に有効にすることをお勧めします。 ソースのバグをできるだけ早くキャッチし、全体的なコストを最小限に抑えるために、ソース分析をローカル開発者のコンピューターで直ちに実行するか、少なくともすべてのコミットまたはプル要求に対して実行します。 バイナリ レベルのバグは、より遅く導入される傾向があるため、リリース前の CI/CD の頻度が低いシナリオ (夜間ビルドや毎週ビルドなど) でバイナリ分析を実行するだけで十分な場合があります。

2.4 ハードコーディングされたシークレットのレビュー

まとめ

ソフトウェア内でシークレットをハードコーディングしないでください。 ソース コードベース全体をスキャンできる信頼性の高いツールを使用して、ソース コードからシークレットを効率的に見つけて削除できます。 シークレットを見つけたら、セキュリティで保護されたストレージとシークレットの使用に関するガイドラインに従って安全な場所に移動します。

問題

"シークレット" とは、ID を確立してリソースへのアクセスを提供するエンティティ、または機密データの署名や暗号化に使用されるエンティティを意味します。 たとえば、パスワード、ストレージ キー、接続文字列、秘密キーなどがあります。 ソフトウェアが必要なときに簡単に取得できるように、ソフトウェア製品にシークレットを保持する必要があります。 ただし、これらのハードコーディングされたシークレットは、検出が容易で、サービスとデータを侵害するために使用できるため、重大または致命的なセキュリティ インシデントにつながる可能性があります。

防止

ソース コードでハードコーディングされたシークレット (プレーン テキストまたは暗号化された BLOB) は、セキュリティの脆弱性です。 ソース コードでシークレットを回避する方法に関する一般的なガイドラインを次に示します。

  • ソース管理に送信する前に、事前チェックツールを使用して、コード内の潜在的なハードコーディングされたシークレットをスキャンしてキャッチします。
  • ソース コードまたは構成ファイルにクリア テキスト資格情報を配置しないでください。
  • クリア テキストの資格情報は、SharePoint、OneNote、ファイル共有などには保存しないでください。 または、電子メール、IM などを介して共有します。
  • 簡単に検出できる復号化キーを使用してシークレットを暗号化しないでください。 たとえば、パスワードを含むファイルと共に PFX ファイルを格納しないでください。
  • 弱い暗号化解除でシークレットを暗号化しないでください。 たとえば、脆弱なパスワードまたは一般的なパスワードを使用して PFX ファイルを暗号化しないでください。
  • 暗号化された資格情報をソース コードに含めないでください。 代わりに、ソースでプレースホルダーを使用し、デプロイ システムで承認されたストアのシークレットに置き換えます。
  • 運用環境のデプロイと同じ原則を、テスト、ステージングなどの環境のシークレットに適用します。 多くの場合、敵対者は管理が不十分であるため、非運用システムをターゲットにし、それらを使用して運用環境にピボットします。
  • デプロイ間 (テスト、ステージング、運用など) 間でシークレットを共有しないでください。

ハードコーディングされたシークレットとは直接関係ありませんが、テスト、開発、運用のシークレットをセキュリティで保護することも忘れないでください。

  • シークレットが公開された可能性がある場合は常に、シークレットを定期的にローテーションします。 シークレットをローテーション/再デプロイする機能を実証することは、セキュリティで保護されたシステムの証拠です。 特に、この機能が存在しないことは、避けられない脆弱性のより強力な証拠です。
  • "テスト資格情報ではリスクが生じません" という一般的な開発者の根拠を説明しないでください。実際には、ほぼ常に行います。
  • シークレットの管理を完全に妨げる可能性がある優れたエンジニアリング ソリューションとして、RBAC/ID ドリブン ソリューションを優先してシークレット (パスワード、ベアラー キーなど) から完全に離れてみてください。

検出

製品のレガシ コンポーネントには、ソース コードに隠されたハードコーディングされたシークレットが含まれている場合があります。 開発者のデスクトップ コンピューターのシークレットがリモート ブランチに入り込み、リリース ブランチにマージされ、意図せずにシークレットが漏えいすることがあります。 ソース コードに隠れている可能性があるシークレットを検出するには、ハードコーディングされたシークレットをコードでスキャンできるツールを使用できます。

修正

ソース コードで資格情報が見つかった場合、公開されているキーを無効にし、公開に基づいてリスク分析を実行することが緊急の必要性です。 システムを実行し続ける必要がある場合でも、次の手順を使用して、シークレット マネージャーの修復を有効にすることができます。

  1. 修復によってマネージド ID への切り替えが許可されている場合、または Azure Key Vault (AKV) などのシークレット マネージャーにドロップする必要がある場合は、まずそれを行います。 次に、更新された ID またはキーを使用して再デプロイします。
  2. 公開されているシークレットを無効にします。
  3. 侵害による潜在的な損害の監査/リスク評価を実行します。

クラウド アプリやサービスで使用される暗号化キーやその他のシークレットを保護するには、適切なアクセス ポリシーで Azure Key Vault を使用します。

露出によって特定の顧客データ/PII が侵害された場合は、他のコンプライアンス/レポート要件が必要になる可能性があります。

無効になったシークレットをソース コードから削除し、ソース コードでシークレットを直接公開しない別のメソッドに置き換えます。 Azure AD などのツールを使用して、可能な限りシークレットを排除する機会を探します。 Azure Active Directory を介してマネージド ID を利用するように認証方法を更新できます)。 承認されたストアのみを使用して、Azure Key Vault (AKV) などのシークレットを格納および管理します。 詳細については、以下を参照してください:

Azure DevOps (AzDO)

AzDO ユーザーは、GitHub Advanced Security for Azure DevOps (GHAzDO) を使用してコードをスキャンできます。 GHAzDO を使用すると、ユーザーはリポジトリでプッシュ保護を有効にして、漏洩する前に潜在的な露出をキャッチすることで、シークレットの公開を防ぐことができます。 Azure DevOps のコードでハードコーディングされたシークレットを検出する方法の詳細については、次の各リンクの「Azure DevOps の Github Advanced Security のシークレット スキャン」を参照してください

GitHub で

シークレット スキャンは、次の 2 つの形式で GitHub.com で使用できます。

  • パートナーのシークレット スキャン アラート。 すべてのパブリック リポジトリで自動的に実行されます。 シークレット スキャン パートナーによって指定されたパターンと一致するすべての文字列が、関連するパートナーに直接報告されます。
  • ユーザーのシークレット スキャン アラート。 GitHub Enterprise Cloud を使用し、GitHub Advanced Security のライセンスを持つ組織が所有するリポジトリに対して、追加のスキャンを有効にして構成できます。 これらのツールは、プライベート リポジトリと内部リポジトリもサポートしています。

GitHub では、パートナーとユーザーのニーズを満たすように構成できるシークレットの既知のパターンが提供されます。 詳細については、以下を参照してください。

Note

GitHub Advanced Security for Azure DevOps では、GitHub ユーザーが既に使用できる同じシークレット スキャン、依存関係スキャン、CodeQL コード スキャン ソリューションが提供され、Azure Repos と Pipelines を保護するために Azure DevOps にネイティブに統合されます。

その他のリソース

2.5 言語と OS で提供されるチェックと保護を使用して実行する

まとめ

バイナリのセキュリティ強化は、コンパイル時のセキュリティ制御を適用することによって行われます。 これには、次のような軽減策が含まれます。

  • コードの悪用可能な脆弱性を防ぐ
  • 悪用に対するセキュリティ防御をトリガーするランタイム検出を有効にし、
  • データの生成とアーカイブを有効にして、セキュリティ インシデントによって引き起こされる損害を制限できます。

バイナリ コンシューマーは、強化の完全な利点を得るために Windows セキュリティ機能を選択する必要があります。

Microsoft では、開発者がより安全で安全なコードを記述して出荷できるように、C++ プロジェクトに固有の一連の機能を提供しています。 C++ 開発者は、実行可能コードを生成する言語に共通するセキュリティ標準にも準拠する必要があります。 Microsoft メイン BinSkim は、このセクションで説明する多くの保護の使用を強制するのに役立つパブリック OSS バイナリ チェックer です。 BinSkim の詳細については、Binskim ユーザー ガイドを参照してください 。 |Github

バイナリ レベルのコントロールは、エンジニアリング プロセスで適用される場所によって異なります。 コンパイラとリンカーのオプションを区別する必要があります。厳密にはコンパイル時、実行時のオーバーヘッドでコード生成を変更し、コード生成を変更して OS 保護との互換性を実現します。

開発者設定では、できるだけ多くの静的分析を有効にし、プライベート データの生成を有効にしてデバッグを高速化することを好む必要があります。 リリース ビルドは、セキュリティ、パフォーマンス、およびその他のコード生成に関する問題の適切な組み合わせに合わせて調整する必要があります。 パブリックとプライベートで使用されるビルド データ (パブリックシンボルとプライベート シンボルなど) を適切に生成および管理するようにリリース プロセスを構成する必要があります。

最新の状態を維持する: 常に最新のコンパイラとツールを使用する

最新の言語サポート、静的分析、コード生成、セキュリティコントロールを活用するために、現在のツールセットを使用してすべてのコードをコンパイルします。 コンパイラは生成されたすべてのコンポーネントに影響を与えるため、ツールの更新に対する回帰の可能性は比較的高くなります。 古いコンパイラを使用すると、チームがコンパイラをアップグレードするのに十分な時間がない可能性があるため、セキュリティ インシデントに対応する際に、是正措置の特定のリスクが生じます。 Microsoft では、コンパイラの更新プログラムを定期的に更新してテストするために、チームが施設を開発することをお勧めします。

セキュリティで保護された開発方法、言語バージョン、フレームワーク/API を使用する

コードでは、開発手法、言語バージョン、フレームワーク、API などを利用して、C++ での安全性とシンプルさを促進することでリスクを最小限に抑える必要があります。

  • ベスト プラクティスに従い、一般的な落とし穴を回避する最新の安全で一貫性のある C++ コードを記述するためのガイダンスについては、C++ コア ガイドラインのガイドライン サポート ライブラリ (GSL) を参照してください。
  • C++ コア ガイドラインで推奨される関数と型については 、Microsoft GSL の実装 を参照してください。
  • リソース セーフな C++ コンテナー、C ランタイム ライブラリ (CRT) のメモリ オーバーフロー保護: リソース セーフである優先 std::vectorstd::string、その保護。 C データを使用する必要がある場合は、セキュリティで 保護されたバージョンの CRT 関数を使用します。これは、バッファーの誤用や未定義の言語動作によるメモリ破損を防ぐために設計されています。
  • セーフInt ライブラリ、算術演算と比較演算で整数オーバーフローから保護します。

セキュリティで保護された依存関係を使用する

バイナリは、安全でないライブラリと依存関係にリンクしないでください。 開発チームは、外部のすべての依存関係を追跡し、これらの脆弱性の影響を受けた場合に、より安全なバージョンに更新することで、これらのコンポーネントの CVE/特定されたセキュリティ脆弱性を解決する必要があります。

コードの実証の保証とセキュリティ対応の効率を最大化する

コンパイルでは、バックドアやその他の悪意のあるコードの導入を検出して防ぐのに役立つ強力なコードの実証保証を有効にする必要があります。 結果として得られるデータは、デバッグと調査にも不可欠であり、セキュリティが侵害された場合に効率的なセキュリティ対応を促進するために、すべてのソフトウェア リリースにアーカイブする必要があります。 次のコンパイラ スイッチは、セキュリティ応答に不可欠な情報を生成します。

  • /ZH:SHA_SHA256 Visual C++ の場合 - 暗号化によってセキュリティで保護されたアルゴリズムを使用して、すべての PDB ソース ファイル ハッシュが生成されるようにします。
  • /Zi( /ZI Visual C++ の デバッグ情報形式) - クラッシュ データやその他の一般使用シナリオを収集するための削除されたシンボルを発行するだけでなく、リリースされたすべてのバイナリのプライベート PDB がビルドによって生成およびアーカイブされるようにします。 バイナリ分析ツールでは、コンパイル時に多くのセキュリティ軽減策が有効になっているかどうかを確認するために、完全なシンボルが必要です。 プライベート シンボルはセキュリティ対応において非常に重要であり、エンジニアが悪用が発生したときに損害を評価して制限するためにレースを行っている場合のデバッグと調査のコストを削減します。
  • /SOURCELINK Visual C++ リンカー - PDB に Sourcelink ファイルを含める: ソース リンクは、バイナリのソース デバッグを提供する言語およびソース管理に依存しないシステムです。 ソース デバッグにより、プレリリース セキュリティ検証とリリース後のインシデント対応の範囲の効率が大幅に向上します。

コード作成時にコンパイラ エラーを有効にして問題を回避する

コンパイルでは、セキュリティ関連のコンパイラ チェックを重大なエラーとして有効にする必要があります。次に例を示します。

バイナリを OS ランタイムのセキュリティ軽減策と互換性のあるものとしてマークする

コンパイラとリンカーの設定では、次のような悪意のあるコード実行を検出して軽減するコード生成機能をオプトインする必要があります。

機密情報の漏えいを防止する

コンパイラ設定では、機密情報検出防止を選択する必要があります。 近年、研究者は、投機的実行などのハードウェア機能に起因する意図しない情報漏えいを発見しました。

ソフトウェア レベルでは、予期せず漏洩した場合、機密データが攻撃者に送信される可能性があります。 ゼロ初期化バッファーやその他のバッファーの誤用に失敗すると、信頼できる API を呼び出す攻撃者にプライベート機密データが漏えいする可能性があります。 このクラスの問題は、前述のように、追加の静的分析を有効にし、セキュリティで保護されたリソース コンテナーを使用することで最適に処理されます。

  • /Qspectre - 投機的実行のサイドチャネル攻撃を 軽減する - 投機的実行によって生成される機密データの漏えいを防ぐバリア命令を挿入します。 これらの軽減策は、機密データをメモリに格納し、信頼境界を越えて動作するコードに対して有効にする必要があります。 パフォーマンスクリティカルなブロックまたはループにランタイム チェックが導入される可能性があるため、Spectre 軽減策を有効にする場合は、適切なベンチマークに対するパフォーマンスへの影響を常に測定することをお勧めします。 これらのコード パスでは、修飾子を使用して軽減策を spectre(nomitigation)declspec 無効にすることができます。 '/Qspectre' を有効にするプロジェクトは、Microsoft ランタイム ライブラリを含め、これらの軽減策を使用してコンパイルされたライブラリにもリンクする必要があります。

2.6 ブラックボックステストケース

まとめ

ブラック ボックス テストは、テストされたコンポーネントの内部動作を知ることに依存しません。 ブラック ボックス テストは、製品の機能のエンド ツー エンドの機能を任意のレイヤーまたはレベルでテストするように設計されています。 ブラック ボックス テストには、機能テスト、UI テスト、パフォーマンス テスト、統合テストを使用できます。 ブラック ボックス テストは、一般的な信頼性と機能の正確性を測定し、製品が期待どおりに動作することを確認するために価値があります。

他のセクションとの関係

これらの種類の要件ベースのテストは、脅威モデルで行われた前提条件を検証し、そのセクションで取り上げた潜在的な脅威をカバーするのに役立ちます。 これらのテストは、製品の個別のコンポーネント 、特に脅威モデルで説明されている信頼境界を越えたコンポーネント間の統合をテストするのに役立ちます。 ブラック ボックス テスト ケースは、ユーザー入力検証のすべての種類のエッジ ケースをテストする場合にも役立ちます。 既知のエッジ ケースとエラー ケースの両方をテストすると便利です。 ファジーは、あまり明白でないケースをテストする場合にも役立ちます。

自動化と回帰

これらのテストを定期的に実行し、結果を以前の実行と比較して、重大な変更やパフォーマンスの低下をキャッチします。 また、これらのテストをさまざまなコンピューターとインストールのセットアップで実行すると、さまざまなアーキテクチャやセットアップの変更によって発生する可能性のある問題に対処するのに役立ちます。

クラッシュ ダンプ

これらのテストは、信頼性に関する問題を見つけるのに役立ち、クラッシュ、ハング、デッドロックなどのさまざまなシナリオをテストできます。 テスト エラーの一部としてクラッシュ ダンプを収集することで、ダンプを Visual Studio に直接インポートして、これらの問題が発生しているコードの部分をさらに調査できます。 Visual Studio 内から機能テストを実行する場合は、ブラック ボックス内でテストが失敗した場所を正確に確認することで、エラーを簡単にレプリケートおよびデバッグでき、修正をすばやくテストできます。

テストのデバッグを開始するには、テスト エクスプローラーを使用した単体テストのデバッグ - Visual Studio (Windows) に関するページを参照してください

Azure の場合

Azure DevOps は、テスト 計画を使用してこれらのテストを管理および検証するのにも役立ちます。 これらのテストを使用して、手動検証による承認を確実に行い、製品の要件に関連付けられている自動テストを実行できます。 Azure Test Plans とそれらを使用して自動テストを実行する方法の詳細については、以下を参照してください。

2.7 コードベースのテストケース

まとめ

コードベースのテスト ケースは、製品のセキュリティと信頼性を維持メイン不可欠な部分です。 これらのテストは小規模で高速で、並列で実行できるように互いに影響を与えるべきではありません。 コードベースのテストは、開発者が開発サイクルを遅くすることを心配することなく、コードに変更を加える場合にいつでも開発マシン上でローカルで簡単に実行できます。

型と他のセクションとの関係

コード ベースのテスト ケースの一般的な種類は次のとおりです。

  • 単体テスト、
  • 複数の入力型を持つ関数をカバーするパラメーター化されたテスト
  • コンポーネント テストを使用して各テスト コンポーネントを分離し、
  • 他のサービスと通信するコードの一部を検証するためのモック テスト。それらのサービス自体を含むようにテストの範囲を拡大する必要はありません。

これらのテストは、記述された内部コードに基づいていますが、ブラック ボックス テストは製品の外部機能要件に基づいています。

目標

これらのテストを通じて、目標はコードに対して高レベルのテスト カバレッジを実現することです。 このカバレッジとギャップが存在する場所を積極的に追跡する必要があります。 より多くのコード パスを実行するテストを追加すると、コードのセキュリティと信頼性に対する全体的な信頼度が向上します。

Visual Studio

Visual Studio のテスト エクスプローラー ツールを使用すると、これらのテストを頻繁に実行し、合格/失敗率とエラーの場所に関するフィードバックをすばやく簡単に取得できます。 テスト フレームワークの多くは、テスト自体の場所でテストの状態を確認する CodeLens 機能もサポートしているため、テストスイートの追加とメインが簡単になります。 テスト エクスプローラーを使用すると、これらのテストを簡単に管理でき、テスト グループ、カスタム テストプレイリスト、フィルター処理、並べ替え、検索などを行うことができます。

詳細については、以下を参照してください:

Visual Studio には、コード カバレッジを追跡するためのツールも付属しています。 これらのツールを使用すると、行ったコード変更が既存のテストで確実にカバーされるようにしたり、テストされていない新しいコード パスをカバーする新しいテストを追加したりできます。 また、このツールでは、コード カバレッジの割合も表示され、全体的なコード品質に対する信頼度を確保するために、ターゲット レベルを上回メインが確実に維持されます。

これらのツールの詳細については、「コード カバレッジ テスト - Visual Studio (Windows)」を参照してください

Azure の場合

Azure DevOps は、ビルド パイプライン プロセスの一部として、製品全体のコード カバレッジの結果を追跡するのにも役立ちます。 詳細については、「コード カバレッジの確認 - Azure Pipelines」を参照してください

2.8 過去のテストケース

まとめ

過去のテスト ケース (回帰テスト ケースとも呼ばれます) は、古い問題が再び再表示されるのを防ぎ、製品の全体的なテスト カバレッジを増やします。 バグが修正されたときに、プロジェクトで対応するテスト ケースも追加されることを確認する必要があります。 時間の経過と共に、修正が行われるにつれて、テスト スイートの全体的な堅牢性が向上し続け、信頼性とセキュリティの保証が向上します。

重要な特性と他のセクションとの関係

バグ回帰をテストするため、これらのテストは迅速かつ簡単に実行できるため、[コード ベースのテスト ケース] と共に実行し、製品の全体的なコード カバレッジに貢献できます。 これに加えて、顧客の実際の例を使用して新しいテスト ケースを刺激することは、テストのカバレッジと品質を向上させる優れた方法です。

Visual Studio

Visual Studio を使用すると、バグを修正するための変更を加えながら、スイートにテストを簡単に追加し、テストとコード カバレッジをすばやく実行して、すべての新しいケースが考慮されるようにすることができます。 テストを記述するコードで問題追跡システムからバグ ID を参照することは、回帰テストを対応する問題に接続する良い方法です。 Azure Boards とテスト プランを Visual Studio と一緒に使用することを好みます。

  • テスト、テスト ケース、および問題を関連付ける。そして
  • 問題とそれに対応するテストのすべての側面を追跡します。

詳細については、以下を参照してください:

最終的に、これらのテストをコード セクションをカバーする単体テスト領域に統合することで、テスト スイートを整理して管理しやすくなります。 テスト エクスプローラーのテスト グループを使用して、一緒に属するテストを効果的に追跡できます。 詳細については、「テスト エクスプローラーを使用した単体テストの実行 - Visual Studio (Windows)」を参照してください

2.9 ファジー

サマリー ファジー (ファジー テストとも呼ばれます) は、プログラムへの入力として無効な、予期しない、またはランダムなデータを提供する自動化されたソフトウェア テスト手法です。 その後、クラッシュ、失敗した組み込み、コンパイラによって挿入されたコード アサーション、潜在的なメモリ リークなどの例外がプログラムによって監視されます。

ガイダンス

攻撃者が制御できる信頼されていない入力を処理する可能性があるすべてのソフトウェアでファジーを使用します。 新しいアプリケーションとその関連するテスト スイートを構築する場合は、できるだけ早く主要なモジュールのファジーを含めます。 ソフトウェアの一部で初めてファジーを実行すると、ほぼ常に、以前は不明だった実際の脆弱性が明らかになります。 ファジーを始めたら、決して停止しないでください。

他のセクションとの関係

ファジーによってエラーが報告されると、バグを示す再現可能なテスト ケースが常に自然に提供されます。 このテスト ケースは、再現、解決、および履歴テスト ケースに追加できます。

アドレスサニタイザー (ASan) やファジーなど、両方のサニタイザーを使用する場合:

  • まず、サニタイザーを有効にして通常のテストを実行して問題があるかどうかを確認し、コードがサニタイザークリーンファジーを開始します。
  • C または C++ の場合、ASan を有効にするランタイム アサーションとメタデータの挿入を自動化するコンパイラがあります。 ASan 用にコンパイルすると、結果のバイナリは、15 以上のカテゴリのメモリ安全性エラーを 0 個の誤検知で正確に診断できるランタイム ライブラリとリンクされます。 ソースがある場合は C または C++ の場合、LibFuzzer を使用します。そのためには、最初に ASan を有効にする必要があります。
  • Java、C#、Python、Rust などを使用して記述されたライブラリの場合は、AFL++ フレームワーク使用します。

主な品質

  • ファジーは、静的プログラム分析、網羅的な機能テスト、手動コード検査によって見落とされることが多い脆弱性を検出します。
  • ファジーは、ソフトウェアのセキュリティと信頼性のバグを見つけるための効果的な方法です。そのため、 Microsoft セキュリティ開発ライフサイクル では、すべての製品のすべての信頼されていないインターフェイスでファジーが必要になります (脅威モデリングも参照)。
  • 信頼されていない入力を処理する可能性があるソフトウェアには、常にファジーを使用します。
  • ファジーは、大規模なデータ パーサーを使用するスタンドアロン アプリケーションに効果的です。

Azure と GitHub CI/CD

LibFuzzer または AFL++ を使用する実行可能ファイルの継続的な作成をサポートするようにビルドを変更します。 OSS ファジーや OneFuzz などのサービスでファジーに必要なコンピューティング リソースを追加できます。

2.10 Web アプリケーションのスキャン

まとめ

Windows 上の Microsoft Visual C++ のスコープ内では、次のことをお勧めします。

  • Web アプリケーションには TypeScript、JavaScript、ASP.NET を使用します。
  • C++ で Web 拡張機能を記述しないでください。 Microsoft は ActiveX を非推奨にしました。
  • コードが Emscripten/WASM にコンパイルされると、C++ やその他のツールは適用されなくなります。
  • Microsoft では、ステートフル REST API ファジーザーである RESTler を提供 しています

概要と主な品質

Web アプリケーション スキャナーは、Web ページをクロールして Web アプリケーションを探索し、セキュリティの脆弱性を調べます。 このクロールには、悪意のある入力の自動生成と、アプリケーションの応答の評価が含まれます。 重要なことに、Web アプリケーションのスキャンでは、次の内容がカバーまたはサポートされている必要があります。

  • 新しいアプリや不明なアプリを含む、ネットワーク内のすべての Web アプリをカタログ化し、少数のアプリから数千にスケーリングします。
  • モバイル デバイスで使用されるソフトウェア バージョン、SOAP および REST API サービス、API の詳細スキャン。
  • DevOps 環境でのアプリケーション開発とデプロイへのセキュリティ プリミティブの挿入。 これらのプリミティブはクローラーで動作します。
  • マルウェア検出。

2.11 チェックイン含まれたソフトウェアコンポーネント

まとめ

他のプログラミング言語で記述されたコードと同じように C++ コードを処理し、会社で採用されているソフトウェアコンポジション分析 (SCA) およびオリジン分析 (OA) ツールを C++ コードに適用します。 ワークフローとセキュリティ スキャンは、CI/CD (継続的インテグレーションと継続的デリバリー) システムの一部として設計する必要があります。

アップストリーム防御

アップストリームの依存関係に対する攻撃のリスクを軽減するには、サードパーティのソース/コンポーネントを、SCA および OA ツールが実行されるエンタープライズ管理資産に格納する必要があります。

  • 次のような脆弱性 (パブリック データベースを含む) が特定されたときに、ツールをスキャンしてアラートを生成する必要があります。 |CVE
  • アプリケーション/リポジトリに含まれるすべてのソフトウェア コンポーネントに対して静的分析を実行して、脆弱なコード パターンを特定します。

依存関係の防御

依存関係の監査を実行してメイン、そのようなすべての発生が SCA および OA ツールに対して考慮され、カバーされていることを検証します。

  • コンポーネントは定期的に監査され、最新の検証済みバージョンに更新される必要があります。
  • パッケージ フィードの依存関係。
  • SCA/OA ツールは、1 つのフィードからのすべてのパッケージ依存関係をカバーし、監査します。

SBOM

次のようなすべての依存関係を一覧表示した SBOM (ソフトウェア部品表) を生成します。

  • origin (URL (Uniform Resource Locator) など)
  • version
  • 整合性 (SHA-256 ソース ハッシュなど)、および決定論的ビルドなどの整合性を検証するためのその他の手段。
  • ソフトウェア依存関係内の SBOM ファイルを要求および監査するか、OSS (オープンソース ソフトウェア) を含むビルドの一部として生成されます。
  • Microsoft は SPDX (ソフトウェア パッケージ データ交換) バージョン 2.2 以降を標準化し、推奨 しています |SBOM ドキュメント形式としての Linux Foundation
  • ビルド決定主義を使用すると、ビットごとの同一のバイナリを独立して生成し、整合性の独立した検証を提供できます。
    • 再現性の第一者または第三者の構成証明
    • 信頼された証明書ソースを介したバイナリ署名などの他の手法でも、バイナリ整合性の一部の保証を提供できます。

その他のリソース

Microsoft ソリューションには、次のガイダンスと製品が含まれています。