GitHubのSecret scanning機能を利用して、StripeのAPIキーを安全に管理する

Stripe APIを利用するには、シークレットキーを利用します。このシークレットキーは、顧客やサブスクリプション・レポートデータなど、Stripeに関する多くの情報にアクセスすることができるため、とても慎重に扱う必要があります。

![スクリーンショット 2024-02-28 15.59.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2366300/dde543a5-40ec-4060-8cd4-32d3668ec373.png)


GitHubでソースコードを管理している場合、GitHubが持つ「[Secret scanning](https://docs.github.com/ja/enterprise-cloud@latest/code-security/secret-scanning/about-secret-scanning#about-secret-scanning-for-partner-patterns)」機能を利用することで、「StripeのAPIキーを誤ってコミット・プッシュしてしまったケース」の予防や検知を行うことができるようになります。

この記事では、Secret scanning機能を有効化し、StripeのAPIキーを安全に扱う方法を紹介します。

## GitHubでSecret scanningを設定する

Secret scanningはGitHubのセキュリティ機能の一つであり、プロジェクトに誤ってコミットされたシークレット情報を検出して通知するサービスです。Code scanningは、リポジトリの[Settings]タブから有効化できます。

 「Security」メニュー内にある「Code scanning alerts」を選択すると、設定画面が開きます。

![スクリーンショット 2023-11-06 9.25.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2366300/d85cebe8-37b3-8b62-2f80-ceb6fa4119f9.png)

ページ中段〜下段に[Secret scanning]セクションがありますので、[Enable]をクリックして有効化しましょう。

![スクリーンショット 2023-11-06 9.25.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2366300/5dad683f-c83a-c0fc-f7a1-3e32f5fdd45f.png)

有効化すると、追加の設定画面が表示されます。

![スクリーンショット 2023-11-06 9.25.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2366300/78ab1871-faed-3975-c3d9-600d9f999d50.png)

### Secret scanningで検出できるStripe APIキーは６種類

Secret scanningの対象には、[StripeのAPIキー](https://docs.github.com/en/code-security/code-scanning/introduction-to-code-scanning/about-code-scanning)も含まれています。テスト・本番それぞれのシークレットキーと制限付きキー、そしてWebhookの署名シークレットの６種類を検知できます。

![スクリーンショット 2023-11-06 13.11.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2366300/b53bedd2-8d73-2ffc-3c42-931efdde6c11.png)
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]にしましょう。

![スクリーンショット 2023-11-06 9.25.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2366300/78ab1871-faed-3975-c3d9-600d9f999d50.png)

これだけで設定が完了しました。

![スクリーンショット 2023-11-06 9.26.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2366300/120a350d-e884-a888-b731-3d29df9fdc62.png)

もしシークレットAPIキーなどの情報が含まれたコミットを`git push`しようとした場合、次のようなエラーが発生します。

```bash
$ 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はリポジトリのセキュリティタブにアラートを表示します。アラートの中では、関連するコードの位置と検出されたシークレット情報のタイプなどがレポートされます。

![スクリーンショット 2023-11-06 9.24.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2366300/d6bdd4ba-19d4-036a-027d-2b13059d8fbc.png)

詳細画面では、「どのようなシークレット情報」が「どのファイルのどこにあるか」を確認できます。

![スクリーンショット 2023-11-06 9.31.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2366300/cab490b1-80a1-0a3f-5391-89e6110b90f4.png)

このレポート画面は、リポジトリの管理者向けに表示されるものですので、第三者がこれを使ってシークレットキーを取得することはできません。ただし「アラートが表示されている = シークレットキーが公開されている状態」ですので、速やかに対応する必要があることには変わりありません。

![スクリーンショット 2023-11-06 9.31.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2366300/acd1422d-21d9-36ea-e6d2-66eb0d4d9e82.png)

また、登録されたメールアドレスにもアラートメールが送られます。

![スクリーンショット 2023-11-06 9.23.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2366300/44d174a9-ec98-4d58-323c-f510a1d2c4ff.png)

## アラートが表示された時の対応方法

もしシークレット情報が公開されたことを検出したら、速やかに以下の処置を行う必要があります。

1. **Stripeダッシュボードにアクセス**
2. **対象のAPIキーの削除または無効化**：


### 制限付きAPIキーの処理

誤って公開された制限付きキーは速やかに**削除**してください。これはStripeダッシュボードから行うことができます。
![スクリーンショット 2023-11-06 9.49.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2366300/7cec8eca-a728-d1ac-bebd-ca5e5a1e098f.png)


### シークレットキーの交換

シークレットキーが漏れた場合、速やかに**新しいキーと交換**する必要があります。交換後は、古いキーが無効になり新しいキーが発行されます。

![スクリーンショット 2023-11-06 9.50.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2366300/dd388cf5-f7ed-9a8f-fd30-677d6335c64e.png)

確認画面で、最終使用日や呼び出しログページへのリンクが表示されます。

![スクリーンショット 2023-11-06 9.50.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2366300/f41b1512-e738-8f39-1a9a-3c3f1a56c308.png)

古いシークレットキーは、「即時」または「1時間後」に無効化することをお勧めします。どちらにするかは、シークレットキーを利用しているアプリケーションやシステムに対する、キーの交換作業がどれくらいかかるかで判断します。

![スクリーンショット 2023-11-06 9.50.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2366300/0b89a8a0-849f-9db6-43b0-08649b56f80e.png)

無効化するタイミングなどを確認し、実行しましょう。

![スクリーンショット 2023-11-06 9.50.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2366300/bee0e511-9ab9-3990-8683-fc7137520db8.png)

シークレットキーが新しいものに変更されました。作成日が操作日に・最終使用日が空欄（ー）になっていれば切り替え成功です。
![スクリーンショット 2023-11-06 9.51.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2366300/12225285-fd48-5971-9f5c-a87136bd0131.png)


### Secret scanningのアラートを更新する

Secret scanningで表示されたアラートは、手動で処理する必要があります。

![スクリーンショット 2023-11-06 9.48.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2366300/e3176bf2-6120-e2f6-f2a3-e67f0827380c.png)

[Close as]ボタンをクリックし、対応状況を選択しましょう。シークレットキーを無効化した場合は、`Revoked`を選択します。もしテスト用のシークレットキーを意図してコミットしている場合などでは、`Used in tests`を利用することもできます。

![スクリーンショット 2023-11-06 13.08.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2366300/0db5b8b5-3e62-9271-9d1d-615a907efffb.png)

このように、GitHubのSecret scanning機能を利用することで、シークレットキーの意図しない公開に速やかに気づくことができ、対応状況などもリポジトリのアラートページから確認することができます。

## secretlintを使ったシークレットキー混入検知

もう一つの予防策として、シークレットキーの混入を検知できる[secretlint](https://github.com/secretlint/secretlint)のようなLintツールを使うこともできます。

secretlintの導入には以下のコマンドを利用します。

```bash
% 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のシークレット情報を検出するための設定を追記します。
```diff_json
{
  "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_*/"
+          }
+        ]
+      }
    }
  ]
}
```

シークレットスキャンを実行するには以下のコマンドを使います。

```bash
npx secretlint "**/*"
```

万一、課題が検出された場合には、それを指摘した報告が出力されます。

```bash

/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`フック](https://git-scm.com/book/ja/v2/Git-%E3%81%AE%E3%82%AB%E3%82%B9%E3%82%BF%E3%83%9E%E3%82%A4%E3%82%BA-Git-%E3%83%95%E3%83%83%E3%82%AF)などに設定することで、そもそもコミットをブロックすることも可能です。

https://github.com/secretlint/secretlint

## まとめ

GitHubのSecret Scanning機能と、secretlintを利用したStripeのAPIキーを安全に管理する方法を紹介しました。これらの機能を利用することで、「コードに直接シークレットキーを記述し、それをコミット・プッシュしてしまう」事故の予防や速やかな検知が行えます。

決済や請求処理・顧客情報など、Stripeのシークレットキーからはビジネスに関する重要な情報にアクセスできます。これらの機能を活用して、より安全なアプリケーション・システム開発を行いましょう。

## 参考リンク

- [GitHubのSecret scanningに関する公式ドキュメント](https://docs.github.com/ja/code-security/secret-scanning/about-secret-scanning)
- [GitHubのSecret scanningのパターン一覧](https://docs.github.com/ja/code-security/secret-scanning/secret-scanning-patterns)
- [リポジトリと組織のプッシュ保護について](https://docs.github.com/ja/code-security/secret-scanning/push-protection-for-repositories-and-organizations)
- [Secret scanningアラートの管理についての公式ドキュメント](https://docs.github.com/ja/code-security/secret-scanning/managing-alerts-from-secret-scanning)

https://docs.stripe.com/keys?locale=ja-JP

https://support.stripe.com/questions/locate-api-keys-in-the-dashboard?locale=ja-JP