Make WordPress Core

Opened 11 years ago

Closed 9 years ago

Last modified 6 weeks ago

#24193 closed enhancement (wontfix)

Anti brute force protection

Reported by: mazzy's profile MAzZY Owned by:
Milestone: Priority: normal
Severity: normal Version: 3.5
Component: Users Keywords: has-patch close
Focuses: Cc:


To protect against hacking should be added to the login form protection from brute force. Now the password can enter an unlimited number of times. It is necessary to limit the number of login attempts.

For example, some variants:
1) Captcha after three unsuccessful attempts
2) Temporary inability to login after three unsuccessful attempts
3) something else

Attachments (5)

sleep.patch (601 bytes) - added by mpol 11 years ago.
add a sleep of 3 seconds if the login failed.
24193.diff (3.3 KB) - added by ericlewis 10 years ago.
24193.1.diff (6.2 KB) - added by ericlewis 10 years ago.
24193.2.diff (7.9 KB) - added by ericlewis 10 years ago.
security.php (3.3 KB) - added by Denis-de-Bernardy 10 years ago.

Download all attachments as: .zip

Change History (31)

#1 @knutsp
11 years ago

1) Captcha is not wanted. Really bad UX.
2) Inability for whom? If per IP it doesn't work for coordinated attacks. If per user anyone can cause the site owner to be blocked. At also generates huge login logs, especially when attacked (a possible DoS attack). Not good.
3) Use a strong password. Some plugins may also limit the login attempts, if that is what you want. A plugin may also hide the login form for robots (obscurity).

The best approach for core is to make it very difficult, or almost impossible, to set a weak password. Strong passwords are real security. There is a feature request for this in ticket #21737.

#2 @johnbillion
11 years ago

There are a lot of complexities involved in preventing brute force attacks, which is why I suggest that this remains in the realm of plugins.

Just one example: I work in an office and everyone working there shares the same IP address. This means that we cannot block an IP address if someone enters an incorrect password X times, because you're not going to be popular when you lock out the entire office.

11 years ago

add a sleep of 3 seconds if the login failed.

#3 @mpol
11 years ago

I'm sure some ideas are possible, not all ideas are bad or unworkable. I like the Captcha idea after 3 failed login attempts.
Another idea is to wait 3 seconds if the password is wrong. Just like SSH does. I'll attach a patch for that (very simple).
I'm sure other ideas are welcome here. There's not a single solution, but some ideas will make it for the attackers less convenient.

#4 @knutsp
11 years ago

I'm afraid that a PHP sleep for some seconds is out of the question for core. It could very easy bring down servers due to overload. At least I fear that.

A captcha, while quite bad and hated, after n failed attempts on same user and IP, could be an acceptable solution.

We should then make a plugin as "proof of concept". It should have no options, but hooks so it's behaviour can be modified by (other) plugins.

A good, simple, clean, well-written plugin may have a chance of being accepted for core consideration.

  1. Must not consume a lot of resources, especially under an attack
  2. Must have neglectible impact when logging the failed login attempts
  3. Must never lock out legitimate users
  4. Must not let anyone making trouble for other users
  5. May be differentiate between users that have a strong password and those who have not
  6. Should provide fallbacks or options for other login plugins like "Sidebar Login"

We must not forget that WordPress has millions of installations, mostly on shared hosting, and we have big multisites. A core thing will be the default for all. In times of attacks it must not make things worse, and it can easily do so.

I'm willing to contribute to such a plugin if we reach consensus on how it should work. Comments from core developers would be very useful.

But in making a plugin, there is a chanche it will have to stay as "yet another login security plugin", and the whole thing regarded as "plugin territory".

#5 @markoheijnen
11 years ago

  • Keywords close added

I recommend for closing this ticket. There should be a better way of protecting but what this ticket is about isn't the way.
Having a strong password makes sense and should be encouraged.

#6 @c3mdigital
11 years ago

  • Keywords close removed
  • Resolution set to wontfix
  • Status changed from new to closed

Plugin realm. See comments

#7 @SergeyBiryukov
11 years ago

  • Milestone Awaiting Review deleted

#8 @ericlewis
10 years ago

  • Resolution wontfix deleted
  • Status changed from closed to reopened

Drupal has had something like this in place since 2009. Maybe we can learn something from their experience.

It doesn't seem too technically challenging to me, and could be a valuable shield against (at least amateur) brute force attacks that users won't even notice.

10 years ago

#9 @ericlewis
10 years ago

attachment:24193.diff is a proof of concept.

It uses an options hash to track number of failed login attempts per IP. If more than 10 failed login attempts happen within a minute, the user is throttled for the rest of that minute.

#10 @ericlewis
10 years ago

  • Keywords has-patch added

#11 @nacin
10 years ago

Two main problems with this:

  • This would quickly balloon the options table and probably crash it. In fact it'd be a fairly effective attack in its own right.
  • It would do nothing to prevent distributed brute-force attempts. One person with huge botnet could trivially do some serious damage with this. You'd need to do per-user stuff, rather than per-IP.
  • OK, three problems. Per-user is tough because then it'd be easy to block a user from logging in legitimately. In fact, it'd be a fairly effective attack in its own right.

It's really, really hard to get this right. That's why every plugin I've seen offers a serious amount of configuration, as if a user is going to know how to best balance legitimate attempts versus dealing with a distributed botnet. It's a terrible, horrible user experience.

#12 @knutsp
10 years ago

The protection must be both per IP and per username.

The default limit must be fairly high, like at least 10 attempts (filterable, of course)

A block on username should cause a email to be sent to the user, allowing to unblock and login once again (using a secret key in the url), or request changing the password.

It's important that a legitimate user may not be blocked by others attacking the account using his/her username. But we have the stored email address and the ability to send an email.

A "last successful login IP" could also be stored for every login, as a one-or-few-item whitelist for each user.

There is no need to save all the failed login attempts. What is needed is the number of failed attempts, for a while, maybe is an incremented number. Any successful login should delete the log for both IP and user.

I am quite sure we can work this out!

Last edited 10 years ago by knutsp (previous) (diff)

#13 @nacin
10 years ago

If we have the ability to send an email (which we may *not*, if the server is not configured right), then we really should be doing two-factor auth via IP whitelisting via email.

#14 follow-up: @knutsp
10 years ago

Not being able to send email is an edge condition, making trouble from the installation and up.

Some sort of whitelisting via email, yes. Some sort of a hard protecting using email as a way around for legitimate users being locked out by a special kind of attack on this protection system itself.

Now we are talking.

#15 in reply to: ↑ 14 ; follow-up: @SergeyBiryukov
10 years ago

Replying to knutsp:

Not being able to send email is an edge condition, making trouble from the installation and up.

FWIW, it's not uncommon on support forums.

#16 @SergeyBiryukov
10 years ago

  • Milestone set to Awaiting Review

#17 in reply to: ↑ 15 ; follow-up: @knutsp
10 years ago

Replying to SergeyBiryukov:

FWIW, it's not uncommon on support forums.

is it possible to detect that email are not sent?

#18 @ericlewis
10 years ago

How about a supplemental CAPTCHA method that is required after X # of failed login attempts within Y amount of time?

10 years ago

#19 @ericlewis
10 years ago

attachment:24193.1.diff is a work in progress towards CAPTCHA-based throttling.

Currently implemented so that after a 10th failed attempt on a user account within 2 minutes, a captcha is displayed on the wp-login page.

There's a lot more to do here. The form submission doesn't even verify the captcha result at this point. However, I think it's a step in the right direction re: Nacin's comments.

  • We only need to update the DB a specific number of times (the number of login attempts allowed) to keep a tally of login attempts within the throttling period.
  • Throttling is user-based, not IP-based.
  • Users will never be locked out, they just need to fill out a CAPTCHA as well as their credentials.
Last edited 10 years ago by ericlewis (previous) (diff)

#20 @Denis-de-Bernardy
10 years ago

Fwiw, I've a quick hack running on my own sites using the following approach:

  1. On login attempt, get the latest_logins user_meta. It's an array of array(date, ip, success) that keeps track of up to three successful login attempts, and up to first three failed ones that occurred after the last successful successful login.
  1. If the last three login attempts are all failed, it locks the user by triggering the reset password procedure alongside setting a user_locked meta. The user_locked meta denies any login attempt, successful or not, until the password is indeed reset (at which point the user_locked meta is deleted).
  1. The user's profile page lists the lastest_logins in a table for information.

Most of the code is related to 3. Points 1 and 2 are maybe 10-20 lines of code, since they're using existing APIs.


Edit: bit more than 10-20 lines, actually… Attaching the relevant file for reference.

Last edited 10 years ago by Denis-de-Bernardy (previous) (diff)

10 years ago

#21 @ericlewis
10 years ago

attachment:24193.2.diff is a working prototype.

Create and store a captcha image in wp-includes/images/, which gets refreshed every ten seconds. There's probably a better place for this, as I know some folks lock down permissions on core folders.

Store an md5 hash of the captcha phrase as a site option. When a user is throttled, show the captcha image, an input field, and a hidden input with the md5 captcha to compare their input against.

Last edited 10 years ago by ericlewis (previous) (diff)

#22 in reply to: ↑ 17 @SergeyBiryukov
10 years ago

Replying to knutsp:

is it possible to detect that email are not sent?

I guess it is since #23642 is fixed. See also #23291.

#23 @designsimply
10 years ago

I found a suggestion from a user that seems maybe applicable. They said they like the way Twitter handles the problem of attacks on password reset forms by offering a option that allows users to require entering the right email address before an email can be triggered:

By default, you can initiate a password reset by entering only your @username. If you check this box, you will be prompted to enter your email address or phone number if you forget your password.

—via user rebeca at

It's a(n ever so) slightly different problem report, but an option like the one they recommended may help nonetheless so I'm posting it here for consideration. :)

#24 @knutsp
9 years ago

  • Keywords close added
  • Version changed from 3.5.1 to 3.5

Plugin territory. Many plugins have this, including Jetpack. Since this ticket was opened, passwords are strong by default. Two-factor login support in core will further address this issue.

#25 @wonderboymusic
9 years ago

  • Milestone Awaiting Review deleted
  • Resolution set to wontfix
  • Status changed from reopened to closed

Plugin material for now, perhaps always

#26 @swissspidy
6 weeks ago

#60720 was marked as a duplicate.

Note: See TracTickets for help on using tickets.