トークンセキュリティモデル
L402トークンは、:で結合された2つの部分で構成されています:
- Macaroon —
{hash, exp}を含むbase64エンコードされたJSON。SHA-256で署名されています。preimageを知らずに偽造することはできません。 - Preimage — SHA-256でハッシュ化したときに、macaroonに埋め込まれたハッシュと一致しなければならない32バイトのシークレット。
リプレイ保護
l402-kitには組み込みのリプレイ保護が含まれています。各preimageは一度しか使用できません:401 Token already usedを返します。
デフォルトストア:インメモリのSet。これは以下を意味します:
- 再起動するとリプレイストアがクリアされる(再起動をまたいでトークンが再利用可能になる)
- 複数のインスタンス間で状態が共有されない
トークンの有効期限
トークンにはexpフィールド(ミリ秒単位のUnixタイムスタンプ)が含まれています。SDKは期限切れのトークンを自動的に拒否します。
デフォルトのTTL:1時間(インボイス作成時にLightningプロバイダーによって設定されます)。
HTTPSは必須
本番環境でL402を平文のHTTPで使用しないでください。 macaroonとpreimageはAuthorizationヘッダーで送信されます。HTTPでは、ネットワーク攻撃者にさらされてしまいます。
レート制限
L402はデータベースを参照するのではなく、暗号学的にトークンを検証するため、コストが低くなっています。しかし、Lightningインボイスの作成(402レスポンス)はLightningプロバイダーのAPIを呼び出します。 DoSを防ぐために、インボイス作成をレートリミッターで保護してください:シークレット管理
APIキーをハードコードしないでください。環境変数を使用してください:.env + dotenv(絶対にgitにコミットしないでください)。
管理エンドポイントの認証
管理エンドポイントや統計エンドポイントを公開する場合、URLクエリパラメーターでシークレットを受け取ることは絶対に避けてください。URLはリバースプロキシ、CDN、クラウドプロバイダーによってクエリ文字列を含む完全な形でログに記録されます。Supabaseキーの管理
SUPABASE_SERVICE_KEY(サーバーサイド専用)とSUPABASE_ANON_KEY(クライアントへの公開が安全)を正しく使い分けてください:
| キー | 用途 | RLSをバイパスするか? |
|---|---|---|
anon | VS Code拡張機能、ブラウザクライアント | いいえ |
service_role | サーバーサイドのAPI関数 | はい |
pro_access)を読み取るサーバーサイドのCloudflare Workersはサービスキーを使用しなければなりません — anonキーは絶対に使用しないでください。機密テーブルのRLSポリシーはanonアクセスを許可すべきではありません。
コンテンツセキュリティポリシー
APIとともにフロントエンドを提供する場合、CSPがL402フローをブロックしないようにしてください:データ管理 — ユーザーデータの削除
ユーザーはVS Code拡張機能内からいつでもすべての支払い履歴とProサブスクリプションを削除できます(設定 → 危険ゾーン)。拡張機能は以下を呼び出します:paymentsテーブル内のowner_address = ?に一致するすべての行pro_accessテーブル内のaddress = ?に一致するすべての行
拡張機能では、削除ボタンが有効になる前にユーザーがLightningアドレスを正確に入力する必要があります — 破壊的な操作に対するGitHubスタイルの確認です。
プライバシーとデータ最小化
l402-kitは動作に必要な最小限のデータを収集するよう設計されています。以下に、保存される内容、その理由、および各フィールドを強化する方法を示します。保存される内容
| テーブル | フィールド | 理由 | 機密性 |
|---|---|---|---|
payments | preimage | リプレイ保護 + 支払い証明 | ⚠️ 中 — 代わりにハッシュ化する(下記参照) |
payments | owner_address | 収益をLightningアドレスに紐付ける | 低 — LightningアドレスはパブリックにPublic |
payments | amount_sats | ダッシュボード統計 | 低 |
payments | endpoint | エンドポイント毎の分析 | 低〜中 |
pro_access | address | Proサブスクリプションの確認 | 低 — パブリック |
waitlist | email | ウェルカムメールとリリースメールの送信 | ⚠️ 高 — 実際のPII、暗号化または省略 |
waitlist | lightning_address | オプションのID信号 | 低 |
preimageをそのまま保存せずハッシュ化する
preimageはLightning支払いが行われたことを証明する32バイトのシークレットです。そのまま保存すると、データベース侵害によってすべての証明が公開されてしまいます。代わりにSHA-256ハッシュを保存してください — これはすでに公開されており(BOLT11インボイスに埋め込まれています)、リプレイ保護には十分です:ウェイトリストのメールアドレスを保護する
メールアドレスはシステム内で唯一の真のPIIです。保護レベルの順に以下のオプションがあります:データ削除前にウォレット所有権を証明する(LNURL-auth)
/api/delete-dataエンドポイントは、Lightningアドレスの実際の所有者からのリクエストのみを受け付けるべきです。LNURL-authを使用して所有権を暗号学的に証明してください — ユーザーはパスワードやアカウントなしで、LightningウォレットのPrivateKeyでサーバーチャレンジに署名します:
Supabaseの状態を含む完全なシーケンスについては、完全なフロー図を参照してください。
これにより、Lightningアドレスを知っている場合でも、他のユーザーのレコードを削除することができなくなります。
チェックリスト
本番稼働前
本番稼働前
- すべてのエンドポイントでHTTPSが強制されている
- APIキーがソースコードではなく環境変数に保存されている
- 管理/統計エンドポイントがヘッダー認証を使用している(
?secret=URLパラメーターではなく) - Supabaseの
service_roleキーがサーバーサイドで使用されている;anonキーはクライアントのみ - 機密Supabaseテーブルに
anonのSELECTポリシーがない - データ削除エンドポイント(
/api/delete-data)がサービスキーを使用し、anonキーを使用していない - インボイス作成にレートリミッターが設定されている
- リプレイ保護がテストされている(preimageを再利用して401を確認)
- トークンの有効期限がテストされている(開発環境で短いTTLを設定し、有効期限後の401を確認)
- preimageがSHA-256ハッシュとして保存されており、生のシークレットではない
- ウェイトリストのメールアドレスが保存時に暗号化されているか、送信後に破棄されている
-
/api/delete-dataがウォレット所有権のLNURL-auth証明を要求している
高トラフィックAPIの場合
高トラフィックAPIの場合
- Redisを使用したリプレイストア(インスタンス間で共有)
- 402レスポンスレートの監視(スパイク = DoSの可能性)
- Lightningプロバイダーのフェイルオーバー(BlinkProvider → LNbitsProviderへのフォールバック)
- Lightningプロバイダーのステータスページ監視(例:status.blink.sv)