個人開発のシークレット管理と漏洩対策【TypeScript × Workers Secrets 実装手順】
結論:シークレットは「入口・実行時・出口」の3層で守る
個人開発で環境変数の漏洩を防ぐなら、次の3層をそろえる。どれか1つだけでは穴が残る。
| 層 | やること | 主な道具 |
|---|---|---|
| 入口 | リポジトリに入れない | .gitignore / gitleaks / pre-commit |
| 実行時 | コードに埋め込まず注入する | Workers Secrets / .dev.vars |
| 出口 | 漏れた前提で捨てる | ローテーション手順書 |
理由は単純だ。漏洩の大半は高度な攻撃ではなく、うっかりコミットと使い回したまま放置から起きる。個人開発はレビュアーがいないぶん、機械的なガードを自分で仕込むしかない。
入口:誤コミットを機械で止める
.gitignore は例外だけ許可する形にする
.env
.env.*
.dev.vars
.dev.vars.*
!.env.example
!.dev.vars.example
追跡するのは .env.example だけにして、キー名のみ共有する。値は空文字にしておく。
pre-commit で gitleaks を走らせる
#!/bin/sh
# .git/hooks/pre-commit (chmod +x を忘れずに)
gitleaks protect --staged --redact --no-banner || {
echo 'シークレットらしき文字列を検出した。commit を中止する。'
exit 1
}
Husky や lefthook を使っているなら、そのフック定義に同じコマンドを置けばよい。CI 側にも gitleaks detect のジョブを足しておくと、フックを入れ忘れた別マシンからの push を拾える。
ただし gitleaks はパターンマッチなので万能ではない。自作の短いトークンや、config.ts にベタ書きした ID は検出されないことがある。「検出ゼロ=安全」とは考えないほうがよい。
実行時:TypeScript で型と検証をまとめる
Cloudflare Workers なら値は wrangler secret に保存し、コードからは Env 経由で読む。
npx wrangler secret put STRIPE_SECRET_KEY
npx wrangler secret list
注意点として、wrangler.toml の [vars] は平文でリポジトリに入る。ここに置いてよいのは公開しても困らない設定値だけだ。API キーやトークンは必ず secret put 側に置く。
型は手書きせず、バリデーションと一緒に定義すると保守が楽になる。
import { z } from 'zod';
const EnvSchema = z.object({
STRIPE_SECRET_KEY: z.string().startsWith('sk_'),
AUTH_SECRET: z.string().min(32),
PUBLIC_SITE_URL: z.string().url(),
});
export type AppEnv = z.infer<typeof EnvSchema>;
export function loadEnv(env: unknown): AppEnv {
const parsed = EnvSchema.safeParse(env);
if (!parsed.success) {
// 値そのものは出力しない。キー名だけ出す
const keys = parsed.error.issues.map((i) => i.path.join('.'));
throw new Error(`環境変数が不正: ${keys.join(', ')}`);
}
return parsed.data;
}
肝は、エラー時に値をログへ出さないこと。設定ミスの調査で console.log(env) を書き、それがログ収集サービスに流れて漏れる事故は実際にある。
ローカル開発では .dev.vars を使う。wrangler dev が自動で読み込み、本番の Secrets とは分離される。ここに本番キーを書かず、テスト用キーを使うこと。決済系はテストキーと本番キーの取り違えがそのまま実害になる。
認証系の値を Workers に載せるときの詰まりどころはAuth.js (NextAuth v5) をCloudflare Workersで動かすときのtrustHost設定にまとめてある。
出口:ローテーション手順を先に書いておく
漏洩時にいちばん時間を食うのは「どこに何のキーがあったか思い出す作業」だ。平常時に台帳を作る。
<!-- docs/secrets.md -->
| キー名 | 発行元 | 使用箇所 | 再発行ページ | 最終更新 |
|---|---|---|---|---|
| STRIPE_SECRET_KEY | Stripe | Worker: checkout | ダッシュボード内APIキー画面 | 2026-06-01 |
ローテーションの手順は「新旧を併用できるか」で変わる。
A. 複数キーを同時に持てるサービス
- 新キーを発行する
wrangler secret putで上書きし、デプロイする- 実際のリクエストで動作確認する
- 旧キーを失効させる
B. キーを1つしか持てないサービス
再発行した瞬間に旧キーが死ぬ。デプロイ完了までの短いダウンタイムを見込み、アクセスの少ない時間帯に実施する。
3〜6か月に1回の棚卸しをカレンダーに登録しておくと、現実的に回る。なお各サービスのキー発行仕様や無料枠の条件は変わりやすいので、実施前に公式の最新情報を確認してほしい。
公開サイトを運用しているなら、キー管理と並行して改ざん監視も検討したい。
のような外部サービスは、自分では気づきにくいスクリプト混入の検知手段になる。
漏洩に気づいたときの初動
- まずキーを失効させる。履歴の削除は後回しでよい
- 発行元のダッシュボードで不正利用の有無を確認する
git filter-repoや BFG で履歴から除去する(force push が必要で、fork されていれば完全には消えない)- GitHub のシークレットスキャン通知メールを無視しない
順番が重要だ。履歴を書き換えても、すでに取得された値は無効化されない。
正直に書いておく注意点
- gitleaks も Secrets も運用が前提。フックを
--no-verifyで素通りさせれば意味がない - Workers Secrets は保存後に値を再表示できない。控えは別途パスワードマネージャーに置く
- 個人開発だと台帳の更新が形骸化しやすい。項目は最小限にして続けられる形にする
背景の原則を体系的に押さえたいなら
![体系的に学ぶ 安全なWebアプリケーションの作り方 第2版[固定版] 脆弱性が生まれる原理と対策の実践](https://m.media-amazon.com/images/I/41WBMf7zcML._SL160_.jpg)
体系的に学ぶ 安全なWebアプリケーションの作り方 第2版[固定版] 脆弱性が生まれる原理と対策の実践
参考価格¥3,080(税込)
いわゆる徳丸本。秘密情報の扱いと攻撃経路の基礎が一冊でそろう
Amazonで最新価格をチェックが定番だ。あわせて

Yubico セキュリティキー YubiKey 5 NFC ログイン/U2F/FIDO2/USB-A ポート/2段階認証/高耐久性/耐衝撃性/防水
参考価格¥10,200(税込)
GitHubの2要素認証をハード鍵にすると、アカウント乗っ取り経路を1つ潰せる
Amazonで最新価格をチェックも検討に値する。
まとめ
入口で機械的に止め、実行時は型と検証付きで注入し、出口のローテーション手順を先に用意する。この3層は半日あれば導入でき、一度入れれば以後は自動で効き続ける。個人開発こそ、判断を人間の注意力に任せない設計が有効だ。