PR #43042 の最近の変更により、/u/check_username.json は IP ごとに 1 分間 10 リクエストに制限されるようになりました。
これにより、通常のサインアップフローでリグレッション(機能の劣化)が発生しているようです。
新しいアカウントを作成する際、Discourse は自動的にユーザー名の可用性を確認します。ユーザーがこの制限に達するためにフォームを繰り返し送信する必要はありません。メールアドレスとユーザー名を入力し、入力中に一時停止し、ユーザー名を変更したり修正したりするだけで、/u/check_username.json へのリクエストが複数回発生する可能性があります。
制限に達すると、サインアップフォームには以下が表示されます:
この操作を多数回実行しました。しばらくしてから再度お試しください。
このエラーはユーザー名フィールドの直下に表示され、レートリミッターが期限切れになるまで、ユーザーが作業を続けることを事実上ブロックします。
ユーザーがどれくらい待てばよいかの表示はなく、ユーザーの視点から見ると、選択したユーザー名やサインアップフォームが壊れているように見えます。
再現手順
- 匿名ユーザーとしてサインアップフォームを開く。
- 有効なメールアドレスを入力する。
- ユーザー名を入力し、変更を数回行い、変更の間にユーザー名の可用性チェックが実行されるようにする。
/u/check_username.jsonが 1 分以内に 10 回以上呼び出されるまで続ける。- ユーザー名フィールドにレートリミッターのエラーが表示され始める:
この操作を多数回実行しました。しばらくしてから再度お試しください。
期待される動作
サインアップフォームを完成させたり修正したりする通常のユーザーは、自動的なユーザー名の可用性チェックによってトリガーされた内部的なレート制限によってブロックされるべきではありません。
悪用の防止のためにレート制限が必要である場合、通常のサインアップの 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 インストールでこれを確認できます。
