I've been having a great chat with @jacobian here about potential security improvements to the Django admin UI:
The admin UI is core to Django's value-prop, and it seems undersecured by modern standards. I wanted to raise the possibility on this list of guarding against brute-force login attempts on admin user accounts.
You could imagine tracking / throttle in two main ways.
1. By originating IP
2. By number of login attempts on a user account
In my view, #2 would be the best starting point - there are going to be a relatively small number of admin accounts on the average Django site. Ergo, focused brute-forcing or spearfishing seems to be a greater threat than getting into an admin account via a lot of scanning.
I am proposing a solution broken into two parts - tracking and enforcing.
Tracking - End goal would be logging SuspiciousOperation if appropriate thresholds were crossed. We’d need to store server-side state. I don’t believe we don’t have a clean heap data structure across all DBs that the Django ORM supports, but we could, say, keep two additional columns on each user object: last_login_attempt_window_start, and num_login_attepts_on_window_start, and checking / updating both on any / all login attempts. Alternatively, simply serializing a Python heap-list for each user may work.
Or we can simply leverage the cache backend to store state.
Enforcing - Rejecting login attempts [on any basis] is probably not a good idea for a default - we can’t guarantee we don’t introduce some other DoS-style attack vector. But there are some NIST/etc guidelines around, say, forcing pauses between login attempts, exponential backoff, forcing email-distributed tokens to be used, etc.
We’re already storing custom auth/session information for the Django user model, so storing state/migrations/etc somewhere wouldn’t be too much of a departure.