リグレッション:新しいcheck_usernameのレート制限が通常の登録フローをブロックする可能性

PR #43042 の最近の変更により、/u/check_username.json は IP ごとに 1 分間 10 リクエストに制限されるようになりました。

これにより、通常のサインアップフローでリグレッション(機能の劣化)が発生しているようです。

新しいアカウントを作成する際、Discourse は自動的にユーザー名の可用性を確認します。ユーザーがこの制限に達するためにフォームを繰り返し送信する必要はありません。メールアドレスとユーザー名を入力し、入力中に一時停止し、ユーザー名を変更したり修正したりするだけで、/u/check_username.json へのリクエストが複数回発生する可能性があります。

制限に達すると、サインアップフォームには以下が表示されます:

この操作を多数回実行しました。しばらくしてから再度お試しください。

このエラーはユーザー名フィールドの直下に表示され、レートリミッターが期限切れになるまで、ユーザーが作業を続けることを事実上ブロックします。

ユーザーがどれくらい待てばよいかの表示はなく、ユーザーの視点から見ると、選択したユーザー名やサインアップフォームが壊れているように見えます。

再現手順

  1. 匿名ユーザーとしてサインアップフォームを開く。
  2. 有効なメールアドレスを入力する。
  3. ユーザー名を入力し、変更を数回行い、変更の間にユーザー名の可用性チェックが実行されるようにする。
  4. /u/check_username.json が 1 分以内に 10 回以上呼び出されるまで続ける。
  5. ユーザー名フィールドにレートリミッターのエラーが表示され始める:
    この操作を多数回実行しました。しばらくしてから再度お試しください。

期待される動作

サインアップフォームを完成させたり修正したりする通常のユーザーは、自動的なユーザー名の可用性チェックによってトリガーされた内部的なレート制限によってブロックされるべきではありません。

悪用の防止のためにレート制限が必要である場合、通常のサインアップの UX は、レート制限のエラーを表示してアカウント作成を妨げるのではなく、適切にデグレード(段階的な機能低下)するべきです。

実際の動作

ユーザーはユーザー名フィールドにインラインの検証エラーを受け取り、レート制限が期限切れになるまで正常に続行できません。

関連する変更

これは以下によって導入されたようです:

PR #43042 – DEV: check_username リクエストを IP ごとにレート制限

現在の実装は以下を使用しています:

RateLimiter.new(
  current_user,
  "check-username-#{request.remote_ip}",
  10,
  1.minute
).performed!

サインアップ UI 自体が複数のユーザー名チェックを生成し得るため、正当な操作の間に 1 分間 10 リクエストという制限に達する可能性があります。

また、リミッターはセッションごとではなく IP ごとであるため、共有 NAT / 公開 IP アドレスの背後にいるユーザーにとって、さらに問題を引き起こす可能性があります。

追加の観察

check_email にも 10 リクエスト/分/IP のリミッターがありますが、その制限を超えた場合、レート制限のエラーをユーザーに表示するのではなく、成功したレスポンスを返します。

したがって、check_username も同様に動作させるのが理にかなっているかもしれません。あるいは:

  • 制限を上げる;

  • 設定可能にする;

  • ユーザー名の提案 / 自動検証リクエストを同じバケットにカウントしないようにする;

  • または、サインアップフローをブロックせずにクライアントサイドでレート制限を処理する。

    PR #43042 の変更後の https://try.discourse.org/ を含む、現在の Discourse インストールでこれを確認できます。

「いいね!」 1