Регистрация: throttle по IP от спама аккаунтов
throttle_register ограничивает частоту POST /api/auth/register с одного IP через тот же LoginThrottle (считаются все попытки). Enumeration ников через 409 не закрываем — ники и так публичны в топе (отмечено в отчёте). #62 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XfTsytzT6TojfmprRDKiV6
This commit is contained in:
@@ -34,6 +34,8 @@ _IP_LIMIT = 20
|
||||
_ACCOUNT_LIMIT = 50
|
||||
# Неверный текущий пароль при смене — на аккаунт.
|
||||
_CURRENT_PASSWORD_LIMIT = 5
|
||||
# Регистраций с одного IP за окно — против спама аккаунтов (#62).
|
||||
_REGISTER_IP_LIMIT = 10
|
||||
|
||||
|
||||
def validate_new_password(password: str) -> None:
|
||||
@@ -87,6 +89,18 @@ def login_player(session: Session, nickname: str, password: str, ip: str | None)
|
||||
return user
|
||||
|
||||
|
||||
def throttle_register(ip: str | None) -> None:
|
||||
"""Ограничивает частоту регистраций с одного IP (спам аккаунтов, #62).
|
||||
|
||||
Считаем каждую попытку (и успешную, и нет), поэтому массовое создание аккаунтов
|
||||
с уникальными никами упирается в предел так же, как повторы по занятому нику.
|
||||
Enumeration ников через 409 NICKNAME_TAKEN не закрываем: ники и так публичны в топе."""
|
||||
ip = ip or "unknown"
|
||||
limits = {f"register-ip:{ip}": _REGISTER_IP_LIMIT}
|
||||
login_throttle.check(limits)
|
||||
login_throttle.fail(limits)
|
||||
|
||||
|
||||
def check_current_password(user: User, current_password: str | None) -> None:
|
||||
"""Сменить уже заданный пароль можно только зная текущий, и подбирать его нельзя:
|
||||
иначе оставленная открытой сессия позволила бы отобрать аккаунт насовсем."""
|
||||
|
||||
@@ -8,7 +8,7 @@ from fastapi import APIRouter, Depends, Request, Response
|
||||
from sqlmodel import Session
|
||||
|
||||
from app.auth.login import establish_session
|
||||
from app.auth.password import login_player
|
||||
from app.auth.password import login_player, throttle_register
|
||||
from app.auth.registry import enabled_methods
|
||||
from app.auth.telegram import TelegramProvider
|
||||
from app.core import security
|
||||
@@ -39,6 +39,7 @@ def password_register(
|
||||
session: Session = Depends(get_session),
|
||||
) -> s.MeRead:
|
||||
"""Регистрация по логину (нику) и паролю. Telegram привязывается позже в профиле."""
|
||||
throttle_register(client_ip(request)) # против спама аккаунтов с одного IP (#62)
|
||||
user = user_service.register_local(session, body.nickname, body.password)
|
||||
audit_service.record(
|
||||
session,
|
||||
|
||||
Reference in New Issue
Block a user