ルール開発プロセス

概要

Secret Detection のルール開発プロセスは、主に特定のシークレット資格情報タイプを識別するための適切な正規表現パターンの作成を含みます。さらに、ルールキーワード、バリデーション正規表現、修復ガイドなどの追加情報を収集する必要があります。このドキュメントではプロセス全体を説明します。

ルールには何が含まれるか?

特定の資格情報タイプのルールは TOML ファイルで定義され、以下のプロパティを含みます。

  • id: ルールの一意の識別子(例: AWSSecretKey)。
  • regex: シークレットを検出するために使用される主要な正規表現パターン。
  • keywords: (オプション)正規表現を適用する前にコンテンツを事前フィルタリングするために役立つキーワードのリスト。パフォーマンスを向上させます。
  • validationRegex: (オプション)検出されたシークレットの周囲のコンテキストを検証するために使用される副次的な正規表現。誤検知を減らします。
  • examples: regex がマッチすべき最大5つのサンプル文字列のリスト。
  • assignmentContext: (オプション)代入のような正規表現パターンを自動生成するための設定。以下を含みます。
    • keywordGroup: 代入の左辺(LHS)で使用されるキーワードとキーワードグループのカンマ区切り文字列。
    • operator: (オプション)代入で使用される演算子(例: =: )。デフォルトは [:=]
    • terminalRegex: (オプション)代入のようなパターンにおけるシークレットの使用終了を一致させる正規表現パターン。
  • tags: (オプション)ルールの性質を分類するタグのリスト(例: Secret Push Protection のルールを有効にするための gitlab_blocking)。

以下は Stripe Live Secret Key のルール定義の例です。

[[rules]]
id = "StripeLiveSecretKey"
keywords = ["sk_live_"]
regex = '''\bsk_live_[A-Za-z0-9]{99}\b'''
validationRegex = "(?i)stripe"
examples = [
  "sk_live_...",
  ...
]
negativeExamples = [
  "sk_live_...",
  ...
]
tags = ["gitlab_blocking"]

ルールプロパティの詳細については、ルールスキーマを参照してください。

secret-detection-rules/rules/mit 内のディレクトリ構造は <company>/<company.toml> として配置されており、<company>.toml ファイルにはその会社の対応する資格情報タイプのすべてのルール定義が含まれています。同じ会社ディレクトリには、その会社のすべての資格情報タイプの修復ガイドが配置されています。

開発プロセス

大まかに言うと、シークレット資格情報タイプの新しいルールを導入するための典型的なステップは次のとおりです。

  1. 前提条件:
    • シークレット資格情報タイプの存在と漏洩リスクを確認する
  2. 正規表現の生成:
    • 資格情報タイプに合致する適切な正規表現パターンを開発する
    • パブリックソースコードリポジトリでパターンの正確性を検証する
    • 誤検知のマッチを特定し、減らすための手順を踏む
  3. 追加ルールプロパティ:
    • 正規表現パターン内の一意のキーワードをルールキーワードとして設定するために特定する
    • パブリックソースから最大5つのマッチングサンプルを収集してルール例として使用する
    • バリデーション正規表現に使用するルールに関連する会社/製品名などの関連キーワードを特定する
  4. 修復ガイド:
    • シークレット侵害が発生した場合に顧客が従うための修復ガイドを生成する

各ステップを詳しく見ていきましょう。

1. 前提条件

新しいルールを作成する前に、資格情報の存在と実際の公開状況を確認することが不可欠です。典型的な方法は、公式ドキュメントソースで資格情報を検索することです。例えば、Google の公式ドキュメントで「Google Cloud Service Account」を検索すると、サービスアカウントの作成と管理というページが見つかり、そこで JSON 形式のサンプルサービスアカウントキーを確認できます。

さらに、資格情報の漏洩リスクを特定することも重要で、これはルールの重大度を定義するのに役立ちます。漏洩リスクはほとんどのドキュメントで明確に定義されていませんが、資格情報のユースケースとセキュリティへの影響に基づいて推測できます。

2. 正規表現の生成

これはプロセス全体で最も重要なステップです。適切に作成された正規表現パターンは高い精度を確保し、誤検知を最小化します。効果的な正規表現パターンを生成するためのガイドラインとツールを示します。

  • 具体性が鍵: シークレット資格情報タイプに可能な限り具体的な正規表現パターンを目指します。一般的な文字列にマッチする可能性のある過度に広いパターンを避けます。
  • 正規表現の互換性: 正規表現が私たちの正規表現エンジン(Hyperscan)と互換性があることを確認します。正規表現を生成する際はサポートされている機能を確認してください。
  • ワード境界: 適切な場所でワード境界(\b)を使用して、正規表現がより大きな文字列のサブセットではなくシークレット全体にマッチするようにします。ワード境界文字は英数字またはアンダースコア(_)以外のすべての文字にマッチするため、正規表現の末尾に追加することが通常役立ちます。ただし、:,、またはその他の記号などの句読点を考慮しない可能性があるため、一部のシークレットタイプでは偽陰性が発生する可能性があることに注意してください。
  • グループ化: 非キャプチャグループ((?:))を使用してパターンを論理的にグループ化し、読みやすさを向上させます。正規表現にはキャプチャグループが最大1つまで存在できます。
  • 特殊文字のエスケープ: シークレット資格情報タイプに現れる可能性のある特殊な正規表現文字をエスケープします。
  • 文字クラス: 特定のタイプの文字を一致させるために文字クラス(\d\w など)を使用する代わりに、常に明示的な文字([a-zA-Z0-9])を定義します。
  • 量指定子: 文字またはグループの出現回数を指定するために、オープンエンドなもの(*+{n,})ではなく、固定または有界範囲の量指定子({n}?、または {n,m})を定義します。これにより過度に許容するマッチのリスクを回避できます。
  • 否定先読み/後読み: 先読み/後読みの使用は許可されていません。これらは特定のパターンやコンテキストを除外するために強力ですが、私たちの正規表現エンジンではサポートされていません。
  • 一般的なシークレットのフォーマット: 多くのシークレットは一般的なパターン(例: prefix_alphanumeric_base64string)に従っています。これらに慣れることで、堅牢なパターンを構築できます。

注意: 正規表現が Hyperscan エンジンの正規表現制約と互換性があることを確認してください。

正規表現の生成とテストのためのツール

  1. Regex101: 正規表現の詳細な説明、マッチのハイライト、サンプルテキストに対するテストを提供する人気のオンライン正規表現テスター。さまざまな正規表現フレーバーをサポートしています。
  2. 正規表現ベースのコード検索: リポジトリ全体でパターンを見つけるために、Grep App またはその他の正規表現ベースの検索機能を持つソースコード管理システムを使用します。

代入のような正規表現パターン

特定の資格情報タイプには、意図したシークレットを一致させ、誤検知のマッチを最小化するのに役立つ独自のキーワードがパターンにあります。例えば、GitLab PAT にはパターンの先頭に glpat- があります。

しかし、多くの資格情報タイプにはそのような独自のパターンがないため、その正規表現は汎用的になるか、UUID や base32/64 エンコードされた文字列のような標準フォーマットと重なり、ランダムな文字列にマッチします。そのような場合、シークレットの存在を確認するためにシークレットの周囲のコンテキストを活用します。現在、代入のようなパターンをチェックしています。

<左辺(LHS)><演算子><右辺(RHS)><終端正規表現>
  • RHS にはシークレット値のみを含める必要があります(例: GitLab PAT パターン)。
  • LHS には資格情報タイプに関連する会社/製品名を含める必要があります。
  • 演算子はコロン(:)、等号(=)などです。
  • 終端正規表現は、代入のようなパターンでの誤検知マッチを避けるためにシークレットの使用終了と一致する適切なパターンである必要があります。

DataDog API Key 資格情報タイプの例を取り上げてみましょう。この資格情報タイプの正規表現パターンは [0-9a-f]{32} となる可能性があります。これは汎用的な16進数文字列パターンです。このパターンが DataDog の API Key のみに一致するようにするために、LHS に dd_api_keydatadog_api_key、およびその他の関連する変数名とケーシングの組み合わせ、RHS に [0-9a-f]{32} を持つ代入のようなパターンをこの文字列の周囲でチェックします。これによりルールの精度が向上します。

代入正規表現の自動生成

dd_api_keydatadog_api_key はこの特定の命名規則(つまり、小文字スネークケース)に従う言語のみをカバーしていますが、いくつかの疑問が生じます。

  • 他の言語と設定ファイルフォーマットの命名規則はどうか?
  • 他の言語と設定ファイルフォーマットをサポートするケーシングのバリアントはどうか?
  • 最小限の労力ですべてのルールの代入パターンを改善したい場合はどうか?

このプロセスを簡素化するために、与えられた入力セットに対して代入のような正規表現パターンを自動生成するユーティリティを導入しました。

: DataDog API Key ルールの場合、必要なのはルール定義で assignmentContext.keywordGroup を定義することだけです。

# id = "DataDogAPIKey"
# regex = '''[0-9a-f]{32}\b'''
...
assignmentContext.keywordGroup = "datadog|dd,api,key"
...

assignmentContext.keywordGroup の値は、LHS に同じ順序で datadog または dd の後に apikey が続く可能性があることを示しています。これにより LHS 上の正規表現リテラルの可能なすべての命名とケーシングの組み合わせが生成され、その後以下のような代入のような正規表現パターン全体が生成されます。

(?:DATADOG_API_KEY|datadog_api_key|datadogApiKey|datadog-api-key|datadog\.api\.key|DatadogApiKey|Datadog-Api-Key|DD_API_KEY|dd_api_key|ddApiKey|dd-api-key|dd\.api\.key|DdApiKey|Dd-Api-Key).{0,8}[:=].{0,8}([0-9a-f]{32}\b)

ルールの regex 値は、ルールセットパッケージが配布される際に上記の生成された正規表現に置き換えられます。代入コンテキストを表現するためのオプションは他にもあります。ルールスキーマドキュメントで詳しく読むことができます。

[!NOTE] 代入のような正規表現パターンは誤検知マッチを確実に減らしますが、コメント内や関数引数としてなど、代入のような式以外の形式でシークレットが直接現れる場合の偽陰性も引き起こします。これは代入のような正規表現パターンを使用する際のトレードオフです。

正規表現の正確性について自信があり、コード検索の結果で多くの誤検知マッチに気づく場合にのみ、代入のような正規表現パターンを使用してください。

3. 追加ルールプロパティ

堅牢な正規表現パターンができたら、ルール定義を完成させるために追加情報を収集する必要があります。これらのプロパティは、シークレット検出ルールの精度と使いやすさを向上させます。

  • ルールキーワード: シークレット内に見つかる一意の文字列またはパターンで、それを識別するのに役立ちます。シークレットを含まないペイロードを素早くフィルタリングして正規表現パターンの実行を避けるために使用されます。

    • 識別方法: シークレットに一貫して含まれる静的なプレフィックス、特定の区切り文字、または一般的なフレーズを探します。例えば、GitLab Personal Access Token の場合は glpat-
    • 注意: ルールキーワードはすべてのルールで必須ではありません。ただし、含まれるとパフォーマンスが大幅に向上する可能性があります。代入のようなパターンの場合、パターンの LHS キーワードが自動的にルールキーワードとして設定されます。
  • ルール例: シークレット資格情報タイプの具体的な例を提供することは、テストとドキュメントにとって重要です。

    • 収集方法: コード検索の結果から、最大5つの異なる実世界の例を選択します。適用可能な場合は、異なるバリエーションやコンテキストをカバーする例を確保します。
    • 用途: これらの例はルールの有効性を検証し、ユーザーと開発者にとって明確な説明として機能します。
  • バリデーション正規表現: この正規表現はルール開発プロセスで使用され、ファイルまたはファイル名のキーワードの存在など、シークレットのコンテキストを一致させることで検出されたシークレットの有効性を確認します。コード検索結果で定義された正規表現を検索することで、生成された正規表現パターンがその資格情報タイプに関連しているかを確認します。

    • 識別方法: 資格情報タイプに関連する会社/製品名または概念を探します。
    • 注意: バリデーション正規表現はすべてのルールで必須ではありません。生成されたパターンの LHS キーワードがシークレットの周囲のコンテキストを表し、バリデーション正規表現ロジックと重なる代入のようなパターンでは特に不要です。
  • タグ: 現在、タグは主に Secret Detection アナライザーに対するルールの利用可能性を決定するために使用されます。タグはデフォルトで空で、すべてのルールは特定せずとも Pipeline ベースの Secret Detection で有効になっています。gitlab_blocking タグを追加すると、Secret Push Protection のルールが有効になります。

4. 修復ガイド

シークレットが検出された場合にユーザーが従うための明確で簡潔な修復ガイドは不可欠です。このガイドは、侵害されたシークレットを取り消してシステムを保護するための実行可能なステップを提供する必要があります。

  • 取り消しステップ: 特定のシークレットタイプを取り消す方法を詳述します。通常、サービスプロバイダーのダッシュボードに移動し、資格情報を見つけて取り消しプロセスを開始することを含みます。
    • : AWS アクセスキーの場合、IAM コンソールに移動し、ユーザーを選択してアクセスキーを無効化または削除します。
  • ローテーションステップ: 適用可能な場合は、取り消し後にシークレットをローテーション(新しいものを生成)する方法の手順を提供します。
  • ベストプラクティス: 環境変数、シークレット管理ツールの使用、またはハードコードされたシークレットを避けるなど、一般的なセキュリティのベストプラクティスを含めます。

修復プロセスに関する情報は、通常会社の公式ドキュメントで入手できます。一部の資格情報タイプでは、他のパブリックソースで入手できる場合があります。

修復ガイドのフォーマット

# <資格情報タイプのわかりやすい名前、例: AWS Session Token>

## 説明

<資格情報タイプの簡単な説明>

## 修復

漏洩したキーに関するセキュリティインシデントの対処に関する一般的なガイダンスについては、GitLab の
[インターネットへの資格情報の漏洩](https://docs.gitlab.com/ee/security/responding_to_security_incidents.html#credential-exposure-to-public-internet)
に関するドキュメントを参照してください。

<資格情報タイプを修復するためのステップ、例: トークンのローテーション>

修復ガイドファイルのルール

  • 修復ガイドファイルは Markdown 形式である必要があります。
  • 各ルールに専用の修復ガイドファイルが存在します。
  • 修復ガイドファイルは、ルールファイルが存在するのと同じディレクトリに作成する必要があります。
  • 特定のルールの修復ガイドは、ルールの id 値と同じファイル名を持つ必要があります。

ルールの検証とテスト

secret-detection-rules リポジトリは、ルールの品質、精度、パフォーマンスを確保するための包括的なテストおよび検証フレームワークを実装しています。テストプロセスは CI/CD パイプラインを通じて自動化されており、複数の検証レイヤーを含んでいます。

自動テストフレームワーク

リポジトリは Go ベースのテストを使用し、ルールのさまざまな側面を検証するいくつかのテストスイートが含まれています。

スキーマ検証テスト

  • JSON スキーマ検証: すべてのルールファイルは、必須プロパティ(idregex)、オプションプロパティ(keywordsvalidationRegexexamplesassignmentContexttags)、プロパティの制約を定義する包括的な JSON スキーマに対して検証されます。
  • TOML フォーマット検証: すべてのルールファイルが適切にフォーマットされた TOML であり、正しくパースできることを確認します。

コアルール検証テスト

  • ルール ID の一意性: すべてのルールファイルにわたって重複するルール ID が存在しないことを確認します。
  • 必須フィールドの検証: すべてのルールが空でないタイトル、説明、修復ガイドを持つことを確認します。
  • 正規表現のコンパイル: すべての regex パターンが RE2 エンジンで正常にコンパイルされ、キャプチャグループが最大1つであることをテストします。
  • 代入コンテキストの検証: assignmentContext を持つルールが gitlab_blocking タグを持たず、適切に定義された keywordGroup を持つことを確認します。

例とキーワードの検証

  • キーワードカバレッジテスト: ルールの正規表現パターンを使用してランダムサンプルを生成し、それぞれがルールのキーワードの少なくとも1つを含むことを確認します。
  • 例の検証: 提供されたすべての例がルールの正規表現パターンに一致し、現実的なシークレットフォーマットを表すことをテストします。

シナリオベースのテスト

リポジトリには、ルールが現実的なコードコンテキストで正しく機能することを検証する包括的なシナリオテストが含まれています。

  • 多言語テスト: Go、PHP、Rust、Shell、XML コンテキストでシークレットをテストします。
  • 設定フォーマットテスト: JSON、YAML、TOML 設定ファイルでの検出を検証します。
  • テンプレートベースの生成: Go テンプレートを使用して、複数の命名規則を持つ現実的なコードシナリオを生成します。

CI/CD パイプライン検証

パイプラインには以下が含まれます。

  • ビルドと検証: Go ユニットテスト、ルールコンパイル、ドキュメント生成、アーティファクトの作成
  • ドキュメントリンティング: スタイルチェック、リンク検証、スペルチェック、散文品質の検証
  • パフォーマンステスト: Blackbird テスト、パフォーマンスベンチマーク、メモリ使用量の検証

手動テストガイドライン

自動テストを超えて、開発者は以下を実施します。

  1. コード検索の検証: 誤検知と偽陰性を特定するための検索結果の手動レビュー
  2. Regex101 テスト: サンプルデータを使用した正規表現パターンのインタラクティブなテスト

品質ゲート

ルールはマージされる前にすべての検証基準を満たす必要があります。

  • すべての自動テストが通過すること
  • スキーマ検証が成功すること
  • Blackbird テストの精度しきい値(70%)を満たすこと
  • チームメンバーからのコードレビュー承認
  • ドキュメントの完全性の確認

参考資料

このマージリクエストでは、異なる方法(一意のプレフィックス、代入ベース、jwt ベース)を持つ複数のルールと自動生成された修復ガイドがルールセットに導入されています。参考として利用できます。