Stripe APIを利用するには、シークレットキーを利用します。このシークレットキーは、顧客やサブスクリプション・レポートデータなど、Stripeに関する多くの情報にアクセスすることができるため、とても慎重に扱う必要があります。
GitHubでソースコードを管理している場合、GitHubが持つ「Secret scanning」機能を利用することで、「StripeのAPIキーを誤ってコミット・プッシュしてしまったケース」の予防や検知を行うことができるようになります。
この記事では、Secret scanning機能を有効化し、StripeのAPIキーを安全に扱う方法を紹介します。
GitHubでSecret scanningを設定する
Secret scanningはGitHubのセキュリティ機能の一つであり、プロジェクトに誤ってコミットされたシークレット情報を検出して通知するサービスです。Code scanningは、リポジトリの[Settings]タブから有効化できます。
「Security」メニュー内にある「Code scanning alerts」を選択すると、設定画面が開きます。
ページ中段〜下段に[Secret scanning]セクションがありますので、[Enable]をクリックして有効化しましょう。
有効化すると、追加の設定画面が表示されます。
Secret scanningで検出できるStripe APIキーは6種類
Secret scanningの対象には、StripeのAPIキーも含まれています。テスト・本番それぞれのシークレットキーと制限付きキー、そしてWebhookの署名シークレットの6種類を検知できます。
https://docs.github.com/en/code-security/code-scanning/introduction-to-code-scanning/about-code-scanning
Push protectionでAPIキーを公開するコミットのプッシュを防止する
意図せずにAPIキーなどをシークレット情報をコミットしてしまった場合に備えて、「シークレットキーが含まれているコミットのプッシュを防止する」機能が用意されています。
先ほどのSecret scanning設定画面で、Push protectionを[Enable]にしましょう。
これだけで設定が完了しました。
もしシークレットAPIキーなどの情報が含まれたコミットをgit push
しようとした場合、次のようなエラーが発生します。
$ git push origin main
Enumerating objects: 5, done.
Counting objects: 100% (5/5), done.
Delta compression using up to 10 threads
Compressing objects: 100% (3/3), done.
Writing objects: 100% (3/3), 427 bytes | 427.00 KiB/s, done.
Total 3 (delta 1), reused 0 (delta 0), pack-reused 0
remote: Resolving deltas: 100% (1/1), completed with 1 local object.
remote: error: GH013: Repository rule violations found for refs/heads/main.
remote: Review all repository rules at http://github.com/hideokamoto-stripe/demo-app/rules?ref=refs%2Fheads%2Fmain
remote:
remote: - GITHUB PUSH PROTECTION
remote: ——————————————————————————————————————————————————————
remote: Resolve the following secrets before pushing again.
remote:
remote: (?) Learn how to resolve a blocked push
remote: https://docs.github.com/code-security/secret-scanning/pushing-a-branch-blocked-by-push-protection
remote:
remote:
remote: —— Stripe API Key ————————————————————————————————————
remote: locations:
remote: - commit: 1fcdb3b095xxxxxxxxx5fae9
remote: path: README.md:4
remote:
remote: (?) To push, remove secret from commit(s) or follow this URL to allow the secret.
remote: https://github.com/hideokamoto-stripe/demo-gh-secret-scanning/security/secret-scanning/unblock-secret/xxxxxxxx
remote:
To github.com:hideokamoto-stripe/demo-gh-secret-scanning.git
! [remote rejected] main -> main (push declined due to repository rule violations)
error: failed to push some refs to 'github.com:hideokamoto-stripe/demo-app.git'
もしこのエラーが発生した場合、「シークレット情報が含まれるコミット」を削除する必要があります。そのため、git reset
やgit rebase
を使ってコミット履歴を修正しましょう。
シークレット情報がpushされた時、なにがおきるか
誤ってシークレット情報をコミットしてしまった場合、GitHubはリポジトリのセキュリティタブにアラートを表示します。アラートの中では、関連するコードの位置と検出されたシークレット情報のタイプなどがレポートされます。
詳細画面では、「どのようなシークレット情報」が「どのファイルのどこにあるか」を確認できます。
このレポート画面は、リポジトリの管理者向けに表示されるものですので、第三者がこれを使ってシークレットキーを取得することはできません。ただし「アラートが表示されている = シークレットキーが公開されている状態」ですので、速やかに対応する必要があることには変わりありません。
また、登録されたメールアドレスにもアラートメールが送られます。
アラートが表示された時の対応方法
もしシークレット情報が公開されたことを検出したら、速やかに以下の処置を行う必要があります。
- Stripeダッシュボードにアクセス
- 対象のAPIキーの削除または無効化:
制限付きAPIキーの処理
誤って公開された制限付きキーは速やかに削除してください。これはStripeダッシュボードから行うことができます。
シークレットキーの交換
シークレットキーが漏れた場合、速やかに新しいキーと交換する必要があります。交換後は、古いキーが無効になり新しいキーが発行されます。
確認画面で、最終使用日や呼び出しログページへのリンクが表示されます。
古いシークレットキーは、「即時」または「1時間後」に無効化することをお勧めします。どちらにするかは、シークレットキーを利用しているアプリケーションやシステムに対する、キーの交換作業がどれくらいかかるかで判断します。
無効化するタイミングなどを確認し、実行しましょう。
シークレットキーが新しいものに変更されました。作成日が操作日に・最終使用日が空欄(ー)になっていれば切り替え成功です。
Secret scanningのアラートを更新する
Secret scanningで表示されたアラートは、手動で処理する必要があります。
[Close as]ボタンをクリックし、対応状況を選択しましょう。シークレットキーを無効化した場合は、Revoked
を選択します。もしテスト用のシークレットキーを意図してコミットしている場合などでは、Used in tests
を利用することもできます。
このように、GitHubのSecret scanning機能を利用することで、シークレットキーの意図しない公開に速やかに気づくことができ、対応状況などもリポジトリのアラートページから確認することができます。
secretlintを使ったシークレットキー混入検知
もう一つの予防策として、シークレットキーの混入を検知できるsecretlintのようなLintツールを使うこともできます。
secretlintの導入には以下のコマンドを利用します。
% npm install secretlint @secretlint/secretlint-rule-preset-recommend @secretlint/secretlint-rule-pattern --save-dev
secretlint --init
で設定ファイルなどを生成できます。
% npx secretlint --init
Create /Users/hideokamoto/stripe/open-source/demo-gh-secret-scanning/.secretlintrc.json
.secretlintrc.json
ファイルがプロジェクトに作成されます。このファイルには以下のようにStripeのシークレット情報を検出するための設定を追記します。
{
"rules": [
{
"id": "@secretlint/secretlint-rule-preset-recommend"
+ },
+ {
+ "id": "@secretlint/secretlint-rule-pattern",
+ "options": {
+ "patterns": [
+ {
+ "name": "Stripe Limited API Key",
+ "pattern": "/rk_(test|live)_*/"
+ },
+ {
+ "name": "Stripe Secret",
+ "pattern": "/sk_(test|live)_*/"
+ },
+ {
+ "name": "Stripe Webhook Secret",
+ "pattern": "/whsec_*/"
+ }
+ ]
+ }
}
]
}
シークレットスキャンを実行するには以下のコマンドを使います。
npx secretlint "**/*"
万一、課題が検出された場合には、それを指摘した報告が出力されます。
/Users/hideokamoto/stripe/demo-gh-secret-scanning/index.js
1:24 error [PATTERN] found matching Stripe Secret: sk_test_ @secretlint/secretlint-rule-pattern
3:24 error [PATTERN] found matching Stripe Webhook Secret: whsec_ @secretlint/secretlint-rule-pattern
✖ 2 problems (2 errors, 0 warnings)
このコマンドをGitのpre-commit
フックなどに設定することで、そもそもコミットをブロックすることも可能です。
まとめ
GitHubのSecret Scanning機能と、secretlintを利用したStripeのAPIキーを安全に管理する方法を紹介しました。これらの機能を利用することで、「コードに直接シークレットキーを記述し、それをコミット・プッシュしてしまう」事故の予防や速やかな検知が行えます。
決済や請求処理・顧客情報など、Stripeのシークレットキーからはビジネスに関する重要な情報にアクセスできます。これらの機能を活用して、より安全なアプリケーション・システム開発を行いましょう。
参考リンク
- GitHubのSecret scanningに関する公式ドキュメント
- GitHubのSecret scanningのパターン一覧
- リポジトリと組織のプッシュ保護について
- Secret scanningアラートの管理についての公式ドキュメント