Skip to content

feat: add proper rate limiting for login endpoints#8081

Draft
szaimen with Copilot wants to merge 2 commits into
mainfrom
copilot/introduce-rate-limiting-login-endpoints
Draft

feat: add proper rate limiting for login endpoints#8081
szaimen with Copilot wants to merge 2 commits into
mainfrom
copilot/introduce-rate-limiting-login-endpoints

Conversation

Copilot AI commented May 12, 2026

Copy link
Copy Markdown
Contributor

Summary

Introduces IP-based rate limiting for the two login endpoints of the AIO master container web interface.

Problem

The previous protection against brute-force attacks was a simple sleep(5) after each failed attempt. This does not prevent parallel attacks or scripted attempts that simply tolerate the delay.

Solution

A new RateLimiter class (backed by APCu, which is already a required PHP extension) tracks failed login attempts per source IP:

  • Limit: 10 failed attempts within a 15-minute rolling window per IP address
  • On exceeded: HTTP 429 Too Many Requests with a Retry-After: 900 header and a clear error message
  • On success: the counter for that IP is reset immediately
  • Rate limited together: both POST /api/auth/login (password login) and GET /api/auth/getlogin (token-based login from Nextcloud admin panel) share the same counter per IP

The sleep(5) delay on failed attempts is kept as an additional cost for individual attempts, complementing the overall rate limit.

Changes

File Change
php/src/Auth/RateLimiter.php New class — APCu-backed per-IP attempt tracking
php/src/Controller/LoginController.php Inject RateLimiter; check/record/reset in TryLogin and GetTryLogin
php/src/DependencyInjection.php Register RateLimiter singleton in the DI container

Implementation notes

  • IP address is taken from REMOTE_ADDR (the direct peer address as seen by the PHP process)
  • The APCu key is a SHA-256 hash of the IP to avoid log/cache pollution and normalise IPv4/IPv6 representations
  • apcu_add(key, 0, TTL) + apcu_inc(key) pattern ensures the TTL is set on first use while keeping the increment atomic
  • is_numeric guard added before casting the cached value to prevent unexpected behaviour from corrupted cache entries

Copilot AI and others added 2 commits May 12, 2026 10:10
- Add RateLimiter class using APCu for per-IP tracking
- Limit failed login attempts to 10 per 15-minute window
- Apply rate limiting in TryLogin (POST /api/auth/login) and GetTryLogin (GET /api/auth/getlogin)
- Return 429 Too Many Requests with Retry-After header when limit exceeded
- Reset counter on successful login
- Register RateLimiter in DependencyInjection container

Agent-Logs-Url: https://github.com/nextcloud/all-in-one/sessions/1ce6e415-a2b7-478c-955f-72f582c157c4

Co-authored-by: szaimen <42591237+szaimen@users.noreply.github.com>
- Add error message body to GetTryLogin 429 response for consistency
- Improve atomicity: use apcu_add(0)+apcu_inc instead of conditional add
- Add is_numeric guard before int cast in isLimitReached

Agent-Logs-Url: https://github.com/nextcloud/all-in-one/sessions/1ce6e415-a2b7-478c-955f-72f582c157c4

Co-authored-by: szaimen <42591237+szaimen@users.noreply.github.com>
Copilot AI requested a review from szaimen May 12, 2026 10:13
@szaimen szaimen added 2. developing Work in progress enhancement New feature or request labels May 12, 2026
@szaimen szaimen added this to the next milestone May 12, 2026
}

public function TryLogin(Request $request, Response $response, array $args) : Response {
$ip = (string)($request->getServerParams()['REMOTE_ADDR'] ?? '');

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess this needs some proper thinking if this is enough, for example for the reverse proxy situation. We might need to add a configuration option that allows to configure the trusted proxies range for caddy

}

public function GetTryLogin(Request $request, Response $response, array $args) : Response {
$ip = (string)($request->getServerParams()['REMOTE_ADDR'] ?? '');

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess this needs some proper thinking if this is enough, for example for the reverse proxy situation. We might need to add a configuration option that allows to configure the trusted proxies range for caddy

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

2. developing Work in progress enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants