fix(backend): アカウント登録のemail enumerationを防ぐ#281
Open
yupix wants to merge 2 commits into
Open
Conversation
新規登録APIで、メールアドレスが既に使用されている場合も未使用時と 同一の201レスポンスを返すようにした。既存メール宛には確認メールの 代わりに「登録済みです」通知メールを送る(password_reset_email等の 既存ジョブ実装パターンに従い、専用の Apalis ジョブ/ワーカーを追加)。 Closes #26
Deploying koyori with
|
| Latest commit: |
27e2301
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://d9f15e44.koyori.pages.dev |
| Branch Preview URL: | https://fix-26-email-enumeration.koyori.pages.dev |
Coverage Report for apps/frontend
File CoverageNo changed files found. |
|
Tip All tests passed and all changes approved!🟢 UI Tests: 21 tests unchanged |
|
コード全体を確認しました。 レビュー結果Medium1. register エンドポイントにレート制限がなく、メールフラッディング攻撃の可能性
bcrypt の計算コスト(100〜500ms/req)で自然にスロットリングされますが、並列10接続でも1時間で数万通の送信要求を投入できてしまいます。攻撃者は既知のメールアドレスを指定するだけでよく、本PR以前(409で即終了・メール未送信)には存在しなかった攻撃面です。
Low
|
register_integration が 500 で落ちていた原因の修正。テストハーネスの ensure_schema は SeaORM の sync() でスキーマを作るが、sync() は entity 定義からカラムデフォルトを生成しないため、register ハンドラーの ensure_system_settings_row が実行する INSERT INTO system_settings (singleton) が user_registration_enabled の NOT NULL 制約違反 (23502) になっていた。マイグレーション (m20260520000000_initial_schema.rs)と同じカラムデフォルトを sync() 後に 付与して解消する。/register を叩く統合テストは今回が初のため、これまで 顕在化していなかった。
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

概要
新規登録 API (
POST /v1/auth/register) で、メールアドレスが既に使用されていても未使用時と同一の 200 系レスポンスを返すようにしました。これまでは既存メールアドレスで登録すると409 Conflictが返っており、レスポンスの違いからメールアドレスの登録有無が判別できてしまう問題(email enumeration)がありました。Closes #26
変更内容
registerハンドラー(apps/backend/crates/handler/src/handlers/auth.rs): ユーザー挿入時に一意制約違反(AuthError::DuplicateEmail)を検知しても、これまでのように409を返さず、新規登録成功時と同一の201 Created+"Register successful"を返すよう分岐を変更already_registered_emailを追加(apps/backend/crates/job/src/already_registered_email.rs)emailのみ(トークン等の機微情報は含めない)。password_reset_email/verification_emailの既存ジョブ実装パターンに従い、専用の Storage・ワーカー・JobState経由のprocessを用意service::already_registered_email_delivery(apps/backend/crates/service/src/already_registered_email_delivery.rs)に分離(password_reset_email_delivery等と同様の構成)AuthError::VerificationEmailEnqueueFailedを使うことで、エラー発生時にも列挙対策が崩れないようにしたAppStateにalready_registered_email_storageを追加し、main.rs/server.rs(ワーカー起動・グレースフルシャットダウン)/ 統合テスト共通ヘルパー (tests/common/mod.rs) に配線Settingsにalready_registered_email_worker_concurrency(デフォルト 1)を追加RegisterErrors)から409 Conflictの定義を削除し、openapi.jsonを再生成(pnpm openapi:export→vp fmt)tests/common/mod.rsのensure_schema)にsystem_settingsのカラムデフォルトを追加。SeaORM のsync()は entity 定義からカラムデフォルトを生成しないため、registerが呼ぶensure_system_settings_rowのINSERT INTO system_settings (singleton)がuser_registration_enabledの NOT NULL 制約違反 (23502) → 500 になっていた(/registerを叩く統合テストは本 PR が初のため、これまで顕在化していなかった)挙動の変化
POST /registerすると409 { "message": "email-already-exists" }201 "Register successful"を返す。既存アカウント宛には「登録済みです」通知メールが非同期で送信される(トークンなし、ログイン画面への案内のみ)テスト
cargo fmt --check/cargo check --workspace --all-targets/cargo clippy --workspace --all-targets— いずれも成功cargo test --workspace --lib— 60件成功(新規ジョブのペイロード回帰テスト含む)--test-threads=1): 37 本すべて PASS(新規追加のregister_integration含む)apps/backend/tests/register_integration.rsを新規追加(新規メール登録時の 201、既存メール登録時も同一の 201・重複ユーザー行が作られないことを検証)openapi.jsonはpnpm openapi:export+vp fmtで再生成し、/registerの409エントリ削除など意図した差分のみであることを確認済み