はじめに:まず深呼吸しよう
「やってしまった」 — GitHubリポジトリの設定を変更していて、気づいたら1分間publicになっていた。
心臓がバクバクして、「全部漏れた」「クレデンシャル悪用される」「会社に報告しなきゃ」と頭の中がパニックになっていませんか?
結論から言います:1分間の公開で即座に壊滅的な被害が出る可能性は、実際にはかなり低いです。
ただし「低い」と「ゼロ」は違います。この記事では、過度に恐れず、かつ必要な対策を確実に行うための 実践的なガイド を提供します。
この記事の対象読者
- 「やっちゃったかも…」と今まさに不安な方
- セキュリティインシデント対応の手順を知りたいエンジニア
- 「本当に危険なの?」を冷静に判断したい方
- 予防策を事前に知っておきたい方
1. まず理解する:1分間の公開で何が起きうるか
1.1 現実的なリスク評価
1分間のpublic公開で起きる可能性
| リスクレベル | 内容 | 詳細 |
|---|---|---|
| 🟢 起きやすい | クローラー/ボットによる自動検出 | GitHubを常時監視するボットは存在する |
| 🟢 起きやすい | GitHub検索インデックスへの追加 | 公開されると検索対象になる可能性 |
| 🟡 確率は低い | 悪意ある人間がたまたま発見 | 1億以上のリポジトリから見つかる確率は低い |
| 🟡 確率は低い | 自動スキャナーがシークレットを検出 | GitHub Secret Scanningが動作する可能性 |
| 🔴 起きにくい | 標的型攻撃による狙い撃ち | 1分では現実的に不可能 |
| 🔴 起きにくい | 大規模なデータ窃取 | 発見→分析→窃取には時間が必要 |
1.2 GitHub Secret Scanningの存在
知っておくべき事実:GitHubには Secret Scanning という機能があり、publicリポジトリで検出されたシークレットは 自動的にプロバイダーに通知 されます。
| プロバイダー | 自動通知 | 自動無効化 |
|---|---|---|
| AWS | ✅ | ✅ (一部) |
| Google Cloud | ✅ | ❌ |
| Azure | ✅ | ❌ |
| Slack | ✅ | ✅ |
| npm | ✅ | ✅ |
| PyPI | ✅ | ❌ |
つまり、1分でも公開された場合、GitHubが検知してプロバイダーに通知している可能性があります。これは「守ってくれている」という意味では良いニュースですが、「検知された=漏洩した」という証拠にもなります。
2. インシデント発生から対応完了までの流れ
以下のフローチャートに従って、落ち着いて対応してください。
flowchart TD
A[🚨 public設定に気づいた] --> B{今もpublicか?}
B -->|はい| C[即座にprivateに戻す]
B -->|いいえ| D[公開期間を確認]
C --> D
D --> E{シークレットが<br>含まれていたか?}
E -->|不明| F[git履歴全体を検索]
E -->|いいえ| G[✅ 低リスク<br>ログ記録のみで完了]
E -->|はい| H{どの種類の<br>シークレット?}
F --> E
H -->|APIキー/トークン| I[🔴 即座にローテーション]
H -->|パスワード| J[🔴 即座に変更]
H -->|SSH鍵| K[🔴 新規生成・旧鍵削除]
H -->|個人情報| L[🟡 法務/コンプライアンス相談]
I --> M[影響範囲の確認]
J --> M
K --> M
L --> M
M --> N{不正利用の<br>痕跡があるか?}
N -->|はい| O[🔴 インシデント対応<br>エスカレーション]
N -->|いいえ| P[📝 記録・報告書作成]
N -->|確認できない| P
P --> Q[✅ 予防策の導入]
O --> Q
Q --> R[完了]
style A fill:#ff6b6b,color:#fff
style C fill:#ff6b6b,color:#fff
style I fill:#ff6b6b,color:#fff
style J fill:#ff6b6b,color:#fff
style K fill:#ff6b6b,color:#fff
style O fill:#ff6b6b,color:#fff
style G fill:#51cf66,color:#fff
style R fill:#51cf66,color:#fff
style L fill:#ffd43b,color:#000
3. 【チェックリスト】今すぐやるべきこと
Phase 1: 初動対応(最初の5分)
## 初動チェックリスト
### 即座に実行
- [ ] リポジトリをprivateに戻したか確認
- [ ] 公開されていた正確な時間を記録(Settings > Danger Zone の変更履歴)
- [ ] 自分以外にアクセスした形跡がないか確認(Insights > Traffic)
### 状況の把握
- [ ] 公開期間: ____分間(__:__ 〜 __:__)
- [ ] リポジトリ名: ____________________
- [ ] 含まれていた可能性のある機密情報:
- [ ] APIキー / トークン
- [ ] パスワード / 認証情報
- [ ] SSH秘密鍵
- [ ] 環境変数ファイル(.env)
- [ ] 個人情報(PII)
- [ ] 社内ドキュメント
- [ ] 上記いずれも含まれていない
Phase 2: シークレットの検索(5〜15分)
# リポジトリ内のシークレットを検索するコマンド
# 1. .envファイルの存在確認
find . -name ".env*" -o -name "*.env" 2>/dev/null
# 2. 一般的なシークレットパターンの検索
grep -rE "(api[_-]?key|secret|password|token|credential)" \
--include="*.{js,ts,py,rb,go,java,yaml,yml,json,xml,conf,config}" \
. 2>/dev/null | head -50
# 3. AWS認証情報の検索
grep -rE "AKIA[0-9A-Z]{16}" . 2>/dev/null
# 4. 秘密鍵の検索
grep -rE "-----BEGIN (RSA |DSA |EC |OPENSSH )?PRIVATE KEY-----" . 2>/dev/null
# 5. git履歴全体での検索(過去のコミットも含む)
git log -p --all -S "password" -- "*.py" "*.js" "*.ts" | head -100
推奨ツール:自動スキャン
# truffleHog(git履歴全体をスキャン)
trufflehog git file://. --only-verified
# gitleaks(高速なシークレット検出)
gitleaks detect --source . --verbose
# git-secrets(AWSに特化)
git secrets --scan
Phase 3: シークレットのローテーション(15分〜)
重要: シークレットが含まれていた場合は、無条件でローテーションしてください。 「たぶん大丈夫」は通用しません。
## ローテーション・チェックリスト
### クラウドプロバイダー
- [ ] AWS Access Key → IAMコンソールで新規作成、旧キー削除
- [ ] GCP Service Account Key → 新規JSON生成、旧キー削除
- [ ] Azure Service Principal → シークレット再生成
### SaaS / API
- [ ] Slack Bot Token → アプリ設定で再生成
- [ ] GitHub Personal Access Token → 新規作成、旧トークン削除
- [ ] Stripe API Key → ダッシュボードでロールまたは再生成
- [ ] SendGrid / Mailgun → API Key再生成
### データベース
- [ ] 本番DBパスワード → 変更後、アプリ側も更新
- [ ] Redis / ElastiCache → AUTH設定更新
### インフラ
- [ ] SSH秘密鍵 → `ssh-keygen` で新規生成、authorized_keysを更新
- [ ] SSL/TLS証明書 → 秘密鍵が漏洩していれば再発行
4. 「本当に漏洩したか」を判断するフローチャート
1分間の公開で「実際に誰かに見られたか」を判断するのは難しいですが、以下の指標が参考になります。
flowchart TD
A[漏洩の可能性を評価] --> B{GitHub Secret Scanning<br>からアラートが来た?}
B -->|はい| C[🔴 GitHubが検知<br>= プロバイダーに通知済み]
B -->|いいえ| D{Traffic Insightsで<br>異常なアクセスがある?}
C --> E[該当シークレットは<br>確実にローテーション]
D -->|はい| F[🟡 人間またはボットが<br>アクセスした可能性]
D -->|いいえ| G{公開中にGitHub検索に<br>インデックスされた?}
F --> E
G -->|はい| H[🟡 検索経由で発見<br>された可能性あり]
G -->|いいえ| I{クラウドプロバイダーから<br>不正利用アラートが来た?}
H --> E
I -->|はい| J[🔴 実際に悪用された<br>緊急対応が必要]
I -->|いいえ| K[🟢 現時点で悪用の<br>証拠なし]
J --> L[インシデント対応チーム<br>エスカレーション]
K --> M[予防的にローテーション<br>推奨]
E --> N[監視を強化して経過観察]
M --> N
L --> N
style C fill:#ff6b6b,color:#fff
style J fill:#ff6b6b,color:#fff
style F fill:#ffd43b,color:#000
style H fill:#ffd43b,color:#000
style K fill:#51cf66,color:#fff
確認方法
# 1. GitHub Secret Scanningアラートの確認
# リポジトリ > Security > Secret scanning alerts
# 2. Traffic Insightsの確認
# リポジトリ > Insights > Traffic
# - Clones数が異常に多くないか
# - Unique visitorsに見知らぬ数がないか
# 3. AWSの場合:CloudTrailでAPIコール確認
aws cloudtrail lookup-events \
--lookup-attributes AttributeKey=AccessKeyId,AttributeValue=AKIA... \
--start-time 2024-01-01T00:00:00Z
# 4. GCPの場合:監査ログ確認
gcloud logging read "protoPayload.authenticationInfo.principalEmail:*" \
--project=YOUR_PROJECT --limit=50
5. 冷静に考える:1分間で何ができるか
攻撃者の視点
| アクション | 1分で可能か | 現実的な確率 |
|---|---|---|
| GitHub検索で発見 | ❌ インデックスに時間がかかる | 極めて低い |
| 自動クローラーが検出 | ⚠️ 運が悪ければ | 低い |
| 手動でリポジトリ発見 | ⚠️ 偶然のアクセス | 極めて低い |
| シークレットを抽出 | ✅ 発見されれば可能 | 発見された場合は高い |
| シークレットを悪用 | ⚠️ 自動化されていれば | 中程度 |
| データを全部ダウンロード | ✅ git cloneは高速 | 発見された場合は高い |
ポイント: 「発見される」確率は低いが、「発見されたら」その後は速い。 だからこそ、予防的なローテーションが重要です。
実際の統計(参考)
- GitHubには1億以上のリポジトリが存在
- 1分間で「あなたの」リポジトリが発見される確率は天文学的に低い
- ただし、シークレットスキャナーは24時間稼働している
- 公開リポジトリは定期的にスキャンされている
6. 報告書テンプレート
会社やチームへの報告が必要な場合、以下のテンプレートを使用してください。
# セキュリティインシデント報告書
## 概要
- **発生日時**: 2024年XX月XX日 HH:MM 〜 HH:MM(約X分間)
- **対象リポジトリ**: organization/repository-name
- **発見者**: [自分の名前]
- **報告日**: 2024年XX月XX日
## インシデント内容
GitHubリポジトリの可視性設定を誤ってprivateからpublicに変更し、
約X分間、インターネット上から閲覧可能な状態となった。
## 影響範囲
### 含まれていた可能性のある機密情報
- [ ] APIキー・トークン: [あり/なし/確認中]
- [ ] 認証情報: [あり/なし/確認中]
- [ ] 個人情報: [あり/なし/確認中]
- [ ] ソースコード: [あり]
### 漏洩の証拠
- GitHub Secret Scanningアラート: [あり/なし]
- Traffic Insights異常: [あり/なし]
- クラウドプロバイダーアラート: [あり/なし]
## 実施した対応
1. [HH:MM] リポジトリをprivateに変更
2. [HH:MM] シークレットの有無を確認
3. [HH:MM] 該当シークレットをローテーション
4. [HH:MM] 監視強化を設定
## ローテーションしたシークレット
| 種類 | 対象 | 完了日時 |
|-----|------|---------|
| AWS Access Key | AKIA... | HH:MM |
| GitHub Token | ghp_... | HH:MM |
## 再発防止策
1. [ ] pre-commitフックでシークレット検出を導入
2. [ ] リポジトリ設定変更時の承認フローを追加
3. [ ] 定期的なシークレットスキャンを自動化
## 結論
現時点で悪用された証拠は[確認されていない/確認された]。
予防的措置として全ての潜在的シークレットをローテーション済み。
継続的な監視を行い、異常があれば追加報告する。
7. 【最重要】.gitignoreしても過去のコミットに残っている問題
これが 最も見落としやすく、最も危険な罠 です。
7.1 なぜ.gitignoreだけでは不十分なのか
flowchart TD
A[最初のコミット] -->|.envを含めてコミット| B[履歴に.envが残る]
B --> C[後から.gitignoreに追加]
C --> D[新規コミットには含まれない]
D --> E[でも過去の履歴には残ったまま]
E --> F[リポジトリをpublic化]
F --> G[🔴 過去のコミットから<br>.envが丸見え]
style A fill:#ff6b6b,color:#fff
style B fill:#ff6b6b,color:#fff
style G fill:#ff6b6b,color:#fff
style C fill:#ffd43b,color:#000
style D fill:#51cf66,color:#fff
よくある勘違い:
- ❌ 「.gitignoreに追加したから大丈夫」
- ❌ 「今の状態では見えないから安全」
- ❌ 「ファイルを削除したから問題ない」
現実:
- ✅ git履歴には全てのコミットが残っている
- ✅
git log -pで過去の全変更が見える - ✅ publicになった瞬間、全履歴が公開される
7.2 自分のリポジトリをチェックする方法
# 過去の全コミットで.envファイルを検索
git log --all --full-history -- "**/.env*"
# 過去の全コミットでシークレットっぽい文字列を検索
git log -p --all -S "password" | head -100
git log -p --all -S "api_key" | head -100
git log -p --all -S "secret" | head -100
# AWS認証情報が過去に含まれていたか
git log -p --all | grep -E "AKIA[0-9A-Z]{16}" | head -20
# 特定ファイルの履歴を確認
git log -p --all -- "**/credentials*"
git log -p --all -- "**/*.pem"
推奨: gitleaksで全履歴スキャン
# インストール
brew install gitleaks # macOS
# または
go install github.com/gitleaks/gitleaks/v8@latest
# 全履歴をスキャン(これが最も確実)
gitleaks detect --source . --verbose --log-opts="--all"
7.3 過去のコミットから削除する方法
注意: この操作は履歴を書き換えるため、force pushが必要になります。
方法1: BFG Repo-Cleaner(推奨・高速)
# BFGをダウンロード
# https://rtyley.github.io/bfg-repo-cleaner/
# .envファイルを全履歴から削除
java -jar bfg.jar --delete-files .env
# 特定の文字列を全履歴から置換
java -jar bfg.jar --replace-text passwords.txt
# passwords.txt の中身例:
# AKIAIOSFODNN7EXAMPLE==>***REMOVED***
# my-secret-password==>***REMOVED***
# クリーンアップ
git reflog expire --expire=now --all
git gc --prune=now --aggressive
# force push(⚠️ 他のクローンに影響)
git push --force
方法2: git filter-repo(公式推奨)
# インストール
pip install git-filter-repo
# 特定ファイルを全履歴から削除
git filter-repo --path .env --invert-paths
# 特定パターンにマッチするファイルを削除
git filter-repo --path-glob '*.pem' --invert-paths
7.4 履歴削除の現実的な判断
履歴削除すべきか?判断フロー
| 質問 | YES | NO |
|---|---|---|
| シークレットをローテーション済み? | 履歴削除は必須ではない(旧情報は無効) | まずローテーションを優先! |
| すでにpublicで公開されていた? | 履歴削除してもclone済みコピーは残る → ローテーションが唯一の対策 | 履歴削除は有効な予防策 |
| 監査・コンプライアンス要件がある? | 履歴削除を実施 | ローテーション済みなら任意 |
重要: 履歴削除は「やらないよりマシ」だが、ローテーションの代わりにはならない。 すでに公開されていた場合、誰かが clone していれば履歴削除は無意味。
7.5 今後の予防策
# 1. コミット前に必ずスキャン
gitleaks protect --staged
# 2. pre-commitフックで自動チェック
# .pre-commit-config.yaml
repos:
- repo: https://github.com/gitleaks/gitleaks
rev: v8.18.0
hooks:
- id: gitleaks
# 3. 新規リポジトリ作成時に最初から.gitignoreを設定
# (後から追加しても履歴には残る)
8. 二度と起こさないための予防策
8.1 シークレットをリポジトリに入れない
# .gitignoreに追加すべき項目(最初のコミット前に!)
.env
.env.*
*.pem
*.key
credentials.json
serviceaccount.json
*secret*
# git-secretsの導入(コミット前にブロック)
brew install git-secrets # macOS
git secrets --install
git secrets --register-aws
8.2 pre-commitフックの導入
# .pre-commit-config.yaml
repos:
- repo: https://github.com/gitleaks/gitleaks
rev: v8.18.0
hooks:
- id: gitleaks
- repo: https://github.com/awslabs/git-secrets
rev: master
hooks:
- id: git-secrets
8.3 GitHub設定の強化
## GitHub設定チェックリスト
### Organization設定(管理者向け)
- [ ] リポジトリ作成時のデフォルトをprivateに設定
- [ ] public変更に管理者承認を必須化
- [ ] Secret Scanningを有効化(Enterprise)
- [ ] Push Protectionを有効化
### 個人設定
- [ ] 二要素認証を有効化
- [ ] Personal Access Tokenの有効期限を設定
- [ ] SSHキーを最新のものに更新
8.4 環境変数管理のベストプラクティス
# 悪い例 ❌
export AWS_ACCESS_KEY_ID="AKIAXXXXXXXXXX"
export AWS_SECRET_ACCESS_KEY="xxxxxxxxxxxx"
# 良い例 ✅
# AWS CLIのプロファイル機能を使用
aws configure --profile myproject
# 開発環境では.envrcとdirenvを使用
# .envrc(.gitignoreに追加済み)
export AWS_PROFILE=myproject
# 本番環境ではシークレットマネージャーを使用
# AWS Secrets Manager / HashiCorp Vault / 1Password CLI
9. よくある質問(FAQ)
Q: 「1分間」は本当に短いのか?
A: コンピュータの世界では1分は長いですが、「発見される」という点では非常に短いです。
- GitHubの検索インデックスは即時ではない
- ボットが巡回していても、全リポジトリを監視しているわけではない
- ただし、「短い」ことと「安全」は別問題
結論: 短いが、ゼロリスクではない。予防的対応を推奨。
Q: ローテーションが面倒で先延ばしにしてしまう
A: 以下の考え方で優先度をつけてください。
| 優先度 | シークレットの種類 | 理由 |
|---|---|---|
| 🔴 最高 | 本番環境のDB認証情報 | 直接的なデータ漏洩リスク |
| 🔴 最高 | AWSルートアカウントキー | 全リソースへのアクセス |
| 🟡 高 | 外部APIキー(課金あり) | 金銭的被害 |
| 🟡 高 | GitHub Token(repo権限) | 他リポジトリへの影響 |
| 🟢 中 | 開発環境の認証情報 | 本番への影響は限定的 |
| 🟢 中 | 読み取り専用APIキー | 情報漏洩のみ |
Q: 上司/チームへの報告は必要か?
A: 以下の基準で判断してください。
報告すべき場合:
- 本番環境の認証情報が含まれていた
- 顧客データ・個人情報が含まれていた
- 会社のセキュリティポリシーで報告が義務付けられている
- 不正利用の痕跡がある
報告は任意の場合:
- 個人プロジェクトのみ
- シークレットが含まれていないことを確認済み
- 開発環境のみで本番への影響なし
Q: 履歴からシークレットを完全に消すべき?
A: ローテーション済みなら、必須ではありません。
# 履歴から削除する場合(force push が必要)
git filter-branch --force --index-filter \
"git rm --cached --ignore-unmatch path/to/secret" \
--prune-empty --tag-name-filter cat -- --all
# または BFG Repo-Cleaner(より高速)
bfg --delete-files .env
注意:
- すでにpublicだった場合、履歴削除しても clone済みのコピーは消せない
- ローテーション済みなら、旧シークレットは無効化されているので被害なし
- 監査要件がある場合のみ履歴削除を検討
Q: 「.gitignoreに追加したから大丈夫」と思っていたのに漏れた
A: これが 最もよくある勘違い です。
.gitignoreは「今後のコミット」にしか効かない。過去のコミットには効果がない。
# こういう流れで事故が起きる
git add .env # ← ここでコミットされる
git commit -m "init"
# ...後日...
echo ".env" >> .gitignore
git add .gitignore
git commit -m "add gitignore"
# → .envは今後追加されないが、最初のコミットには残っている!
確認方法:
# 過去のコミットに.envが含まれていないか確認
git log --all --full-history -- "**/.env*"
# 全履歴スキャン
gitleaks detect --source . --verbose --log-opts="--all"
対策: 詳しくは「7. .gitignoreしても過去のコミットに残っている問題」を参照。
10. まとめ:パニックではなくプロセスで対応する
❌ やってはいけないこと
| NG行動 | 理由 |
|---|---|
| パニックになって何もしない | 時間が経つほど被害が拡大する可能性 |
| 「たぶん大丈夫」で放置 | 確認しないと本当に大丈夫かわからない |
| 証拠を消して隠蔽 | 後から調査できなくなる、信頼を失う |
✅ やるべきこと
| 行動 | 効果 |
|---|---|
| まず状況を記録 | 正確な対応と報告が可能になる |
| チェックリストに沿って対応 | 漏れなく確認できる |
| 予防的にローテーション | 最悪のケースを防げる |
| 再発防止策を導入 | 同じ失敗を繰り返さない |
最後に: セキュリティインシデントは誰にでも起こりえます。重要なのは「起こさないこと」ではなく「起きた時に適切に対応できること」です。この記事のチェックリストをブックマークしておき、もしもの時に冷静に対応できるようにしておきましょう。
参考リンク
- GitHub Secret Scanning
- GitHub Push Protection
- gitleaks
- truffleHog
- git-secrets
- BFG Repo-Cleaner - git履歴からシークレットを削除
- git-filter-repo - Git公式推奨の履歴書き換えツール
- AWS Security Best Practices