<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>limit login attempts Archives - Developry Plugins</title>
	<atom:link href="https://developryplugins.com/tag/limit-login-attempts/feed/" rel="self" type="application/rss+xml" />
	<link>https://developryplugins.com/tag/limit-login-attempts/</link>
	<description></description>
	<lastBuildDate>Mon, 24 Nov 2025 11:17:58 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	

<image>
	<url>https://developryplugins.com/wp-content/uploads/2026/06/cropped-favicon-alt-32x32.webp</url>
	<title>limit login attempts Archives - Developry Plugins</title>
	<link>https://developryplugins.com/tag/limit-login-attempts/</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>How to Block Brute Force Attacks on WordPress Login Pages</title>
		<link>https://developryplugins.com/how-to-block-brute-force-attacks-on-wordpress-login-pages/</link>
		
		<dc:creator><![CDATA[Krasen Slavov]]></dc:creator>
		<pubDate>Mon, 10 Aug 2026 09:00:00 +0000</pubDate>
				<category><![CDATA[WordPress Security & Protection]]></category>
		<category><![CDATA[brute force protection]]></category>
		<category><![CDATA[firewall]]></category>
		<category><![CDATA[limit login attempts]]></category>
		<category><![CDATA[login security]]></category>
		<category><![CDATA[wordpress security]]></category>
		<guid isPermaLink="false">https://developryplugins.com/?p=130</guid>

					<description><![CDATA[<p>Brute force attacks on WordPress login pages are relentless. Bots try thousands of username/password combinations until they gain access. These attacks consume server resources, slow down your site, and eventually...</p>
<p>The post <a href="https://developryplugins.com/how-to-block-brute-force-attacks-on-wordpress-login-pages/">How to Block Brute Force Attacks on WordPress Login Pages</a> appeared first on <a href="https://developryplugins.com">Developry Plugins</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p><!-- @format --></p>
<p>Brute force attacks on WordPress login pages are relentless. Bots try thousands of username/password combinations until they gain access. These attacks consume server resources, slow down your site, and eventually succeed against weak passwords.</p>
<p>This guide provides multiple defensive layers to block brute force attacks, from limiting login attempts to IP whitelisting and CAPTCHA implementation.</p>
<h2 id="understanding-brute-force-attacks">Understanding Brute Force Attacks</h2>
<h3 id="how-they-work">How They Work</h3>
<p>Attackers use automated scripts to try common passwords against wp-login.php:</p>
<pre><code>admin / password
admin / 123456
admin / admin123
administrator / password
...thousands more combinations</code></pre>
<h3 id="signs-of-an-attack">Signs of an Attack</h3>
<ul>
<li>Hundreds of failed login attempts in logs</li>
<li>Increased server CPU/memory usage</li>
<li>Slow admin dashboard</li>
<li>Email flood of failed login notifications</li>
<li>IP addresses from foreign countries</li>
<li>Automated bot patterns (rapid-fire attempts)</li>
</ul>
<h2 id="layer-1-limit-login-attempts">Layer 1: Limit Login Attempts</h2>
<h3 id="using-limit-login-attempts-reloaded">Using Limit Login Attempts Reloaded</h3>
<div class="sourceCode" id="cb2">
<pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true"></a><span class="co"># Install via WP-CLI</span></span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true"></a><span class="ex">wp</span> plugin install limit-login-attempts-reloaded --activate</span></code></pre>
</div>
<p><strong>Recommended Settings:</strong></p>
<ul>
<li><strong>Allowed attempts:</strong> 4</li>
<li><strong>Lockout duration:</strong> 20 minutes</li>
<li><strong>Reset after:</strong> 12 hours</li>
<li><strong>Long lockout:</strong> 24 hours after 4 lockouts</li>
</ul>
<p><strong>Manual Implementation:</strong></p>
<div class="sourceCode" id="cb3">
<pre class="sourceCode php"><code class="sourceCode php"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true"></a><span class="co">// In functions.php or custom plugin</span></span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true"></a>add_action<span class="ot">(</span><span class="st">&#39;wp_login_failed&#39;</span><span class="ot">,</span> <span class="st">&#39;track_failed_login&#39;</span><span class="ot">);</span></span>
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true"></a></span>
<span id="cb3-4"><a href="#cb3-4" aria-hidden="true"></a><span class="kw">function</span> track_failed_login<span class="ot">(</span><span class="kw">$username</span><span class="ot">)</span> {</span>
<span id="cb3-5"><a href="#cb3-5" aria-hidden="true"></a>    <span class="kw">$ip</span> = <span class="kw">$_SERVER</span><span class="ot">[</span><span class="st">&#39;REMOTE_ADDR&#39;</span><span class="ot">];</span></span>
<span id="cb3-6"><a href="#cb3-6" aria-hidden="true"></a>    <span class="kw">$attempts</span> = get_transient<span class="ot">(</span><span class="st">&#39;failed_login_&#39;</span> . <span class="kw">$ip</span><span class="ot">)</span> <span class="ot">?:</span> <span class="dv">0</span><span class="ot">;</span></span>
<span id="cb3-7"><a href="#cb3-7" aria-hidden="true"></a>    <span class="kw">$attempts</span>++<span class="ot">;</span></span>
<span id="cb3-8"><a href="#cb3-8" aria-hidden="true"></a></span>
<span id="cb3-9"><a href="#cb3-9" aria-hidden="true"></a>    set_transient<span class="ot">(</span><span class="st">&#39;failed_login_&#39;</span> . <span class="kw">$ip</span><span class="ot">,</span> <span class="kw">$attempts</span><span class="ot">,</span> <span class="dv">20</span> * <span class="kw">MINUTE_IN_SECONDS</span><span class="ot">);</span></span>
<span id="cb3-10"><a href="#cb3-10" aria-hidden="true"></a></span>
<span id="cb3-11"><a href="#cb3-11" aria-hidden="true"></a>    <span class="kw">if</span> <span class="ot">(</span><span class="kw">$attempts</span> &gt;= <span class="dv">5</span><span class="ot">)</span> {</span>
<span id="cb3-12"><a href="#cb3-12" aria-hidden="true"></a>        <span class="co">// Lock out this IP</span></span>
<span id="cb3-13"><a href="#cb3-13" aria-hidden="true"></a>        set_transient<span class="ot">(</span><span class="st">&#39;lockout_&#39;</span> . <span class="kw">$ip</span><span class="ot">,</span> <span class="kw">true</span><span class="ot">,</span> <span class="kw">HOUR_IN_SECONDS</span><span class="ot">);</span></span>
<span id="cb3-14"><a href="#cb3-14" aria-hidden="true"></a>        wp_die<span class="ot">(</span><span class="st">&#39;Too many failed login attempts. Please try again in 1 hour.&#39;</span><span class="ot">);</span></span>
<span id="cb3-15"><a href="#cb3-15" aria-hidden="true"></a>    }</span>
<span id="cb3-16"><a href="#cb3-16" aria-hidden="true"></a>}</span>
<span id="cb3-17"><a href="#cb3-17" aria-hidden="true"></a></span>
<span id="cb3-18"><a href="#cb3-18" aria-hidden="true"></a><span class="co">// Check before allowing login</span></span>
<span id="cb3-19"><a href="#cb3-19" aria-hidden="true"></a>add_filter<span class="ot">(</span><span class="st">&#39;authenticate&#39;</span><span class="ot">,</span> <span class="st">&#39;check_lockout&#39;</span><span class="ot">,</span> <span class="dv">30</span><span class="ot">,</span> <span class="dv">3</span><span class="ot">);</span></span>
<span id="cb3-20"><a href="#cb3-20" aria-hidden="true"></a></span>
<span id="cb3-21"><a href="#cb3-21" aria-hidden="true"></a><span class="kw">function</span> check_lockout<span class="ot">(</span><span class="kw">$user</span><span class="ot">,</span> <span class="kw">$username</span><span class="ot">,</span> <span class="kw">$password</span><span class="ot">)</span> {</span>
<span id="cb3-22"><a href="#cb3-22" aria-hidden="true"></a>    <span class="kw">$ip</span> = <span class="kw">$_SERVER</span><span class="ot">[</span><span class="st">&#39;REMOTE_ADDR&#39;</span><span class="ot">];</span></span>
<span id="cb3-23"><a href="#cb3-23" aria-hidden="true"></a></span>
<span id="cb3-24"><a href="#cb3-24" aria-hidden="true"></a>    <span class="kw">if</span> <span class="ot">(</span>get_transient<span class="ot">(</span><span class="st">&#39;lockout_&#39;</span> . <span class="kw">$ip</span><span class="ot">))</span> {</span>
<span id="cb3-25"><a href="#cb3-25" aria-hidden="true"></a>        <span class="kw">return</span> <span class="kw">new</span> WP_Error<span class="ot">(</span><span class="st">&#39;lockout&#39;</span><span class="ot">,</span> <span class="st">&#39;Account locked due to too many failed attempts.&#39;</span><span class="ot">);</span></span>
<span id="cb3-26"><a href="#cb3-26" aria-hidden="true"></a>    }</span>
<span id="cb3-27"><a href="#cb3-27" aria-hidden="true"></a></span>
<span id="cb3-28"><a href="#cb3-28" aria-hidden="true"></a>    <span class="kw">return</span> <span class="kw">$user</span><span class="ot">;</span></span>
<span id="cb3-29"><a href="#cb3-29" aria-hidden="true"></a>}</span></code></pre>
</div>
<h2 id="layer-2-add-captcha-protection">Layer 2: Add CAPTCHA Protection</h2>
<h3 id="google-recaptcha-v3-integration">Google reCAPTCHA v3 Integration</h3>
<div class="sourceCode" id="cb4">
<pre class="sourceCode php"><code class="sourceCode php"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true"></a><span class="co">// Add to functions.php</span></span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true"></a></span>
<span id="cb4-3"><a href="#cb4-3" aria-hidden="true"></a><span class="co">// Enqueue reCAPTCHA script</span></span>
<span id="cb4-4"><a href="#cb4-4" aria-hidden="true"></a>add_action<span class="ot">(</span><span class="st">&#39;login_enqueue_scripts&#39;</span><span class="ot">,</span> <span class="st">&#39;add_recaptcha_to_login&#39;</span><span class="ot">);</span></span>
<span id="cb4-5"><a href="#cb4-5" aria-hidden="true"></a></span>
<span id="cb4-6"><a href="#cb4-6" aria-hidden="true"></a><span class="kw">function</span> add_recaptcha_to_login<span class="ot">()</span> {</span>
<span id="cb4-7"><a href="#cb4-7" aria-hidden="true"></a>    <span class="kw">?&gt;</span></span>
<span id="cb4-8"><a href="#cb4-8" aria-hidden="true"></a>    &lt;script src=<span class="st">&quot;https://www.google.com/recaptcha/api.js&quot;</span> async defer&gt;&lt;/script&gt;</span>
<span id="cb4-9"><a href="#cb4-9" aria-hidden="true"></a>    &lt;script&gt;</span>
<span id="cb4-10"><a href="#cb4-10" aria-hidden="true"></a>    <span class="kw">function</span> onSubmit<span class="ot">(</span>token<span class="ot">)</span> {</span>
<span id="cb4-11"><a href="#cb4-11" aria-hidden="true"></a>        document.getElementById<span class="ot">(</span><span class="st">&quot;loginform&quot;</span><span class="ot">)</span>.submit<span class="ot">();</span></span>
<span id="cb4-12"><a href="#cb4-12" aria-hidden="true"></a>    }</span>
<span id="cb4-13"><a href="#cb4-13" aria-hidden="true"></a>    &lt;/script&gt;</span>
<span id="cb4-14"><a href="#cb4-14" aria-hidden="true"></a>    &lt;<span class="ot">?</span>php</span>
<span id="cb4-15"><a href="#cb4-15" aria-hidden="true"></a>}</span>
<span id="cb4-16"><a href="#cb4-16" aria-hidden="true"></a></span>
<span id="cb4-17"><a href="#cb4-17" aria-hidden="true"></a><span class="co">// Add reCAPTCHA to login form</span></span>
<span id="cb4-18"><a href="#cb4-18" aria-hidden="true"></a>add_action<span class="ot">(</span><span class="st">&#39;login_form&#39;</span><span class="ot">,</span> <span class="st">&#39;display_recaptcha&#39;</span><span class="ot">);</span></span>
<span id="cb4-19"><a href="#cb4-19" aria-hidden="true"></a></span>
<span id="cb4-20"><a href="#cb4-20" aria-hidden="true"></a><span class="kw">function</span> display_recaptcha<span class="ot">()</span> {</span>
<span id="cb4-21"><a href="#cb4-21" aria-hidden="true"></a>    <span class="kw">?&gt;</span></span>
<span id="cb4-22"><a href="#cb4-22" aria-hidden="true"></a>    &lt;div <span class="kw">class</span>=<span class="st">&quot;g-recaptcha&quot;</span> data-sitekey=<span class="st">&quot;YOUR_SITE_KEY&quot;</span> data-callback=<span class="st">&quot;onSubmit&quot;</span>&gt;&lt;/div&gt;</span>
<span id="cb4-23"><a href="#cb4-23" aria-hidden="true"></a>    &lt;<span class="ot">?</span>php</span>
<span id="cb4-24"><a href="#cb4-24" aria-hidden="true"></a>}</span>
<span id="cb4-25"><a href="#cb4-25" aria-hidden="true"></a></span>
<span id="cb4-26"><a href="#cb4-26" aria-hidden="true"></a><span class="co">// Verify reCAPTCHA</span></span>
<span id="cb4-27"><a href="#cb4-27" aria-hidden="true"></a>add_filter<span class="ot">(</span><span class="st">&#39;authenticate&#39;</span><span class="ot">,</span> <span class="st">&#39;verify_recaptcha&#39;</span><span class="ot">,</span> <span class="dv">30</span><span class="ot">,</span> <span class="dv">3</span><span class="ot">);</span></span>
<span id="cb4-28"><a href="#cb4-28" aria-hidden="true"></a></span>
<span id="cb4-29"><a href="#cb4-29" aria-hidden="true"></a><span class="kw">function</span> verify_recaptcha<span class="ot">(</span><span class="kw">$user</span><span class="ot">,</span> <span class="kw">$username</span><span class="ot">,</span> <span class="kw">$password</span><span class="ot">)</span> {</span>
<span id="cb4-30"><a href="#cb4-30" aria-hidden="true"></a>    <span class="kw">if</span> <span class="ot">(</span><span class="kw">empty</span><span class="ot">(</span><span class="kw">$_POST</span><span class="ot">[</span><span class="st">&#39;g-recaptcha-response&#39;</span><span class="ot">]))</span> {</span>
<span id="cb4-31"><a href="#cb4-31" aria-hidden="true"></a>        <span class="kw">return</span> <span class="kw">new</span> WP_Error<span class="ot">(</span><span class="st">&#39;captcha_failed&#39;</span><span class="ot">,</span> <span class="st">&#39;Please complete the reCAPTCHA.&#39;</span><span class="ot">);</span></span>
<span id="cb4-32"><a href="#cb4-32" aria-hidden="true"></a>    }</span>
<span id="cb4-33"><a href="#cb4-33" aria-hidden="true"></a></span>
<span id="cb4-34"><a href="#cb4-34" aria-hidden="true"></a>    <span class="kw">$recaptcha</span> = <span class="kw">$_POST</span><span class="ot">[</span><span class="st">&#39;g-recaptcha-response&#39;</span><span class="ot">];</span></span>
<span id="cb4-35"><a href="#cb4-35" aria-hidden="true"></a>    <span class="kw">$secret_key</span> = <span class="st">&#39;YOUR_SECRET_KEY&#39;</span><span class="ot">;</span></span>
<span id="cb4-36"><a href="#cb4-36" aria-hidden="true"></a></span>
<span id="cb4-37"><a href="#cb4-37" aria-hidden="true"></a>    <span class="kw">$response</span> = wp_remote_post<span class="ot">(</span><span class="st">&#39;https://www.google.com/recaptcha/api/siteverify&#39;</span><span class="ot">,</span> <span class="ot">[</span></span>
<span id="cb4-38"><a href="#cb4-38" aria-hidden="true"></a>        <span class="st">&#39;body&#39;</span> =&gt; <span class="ot">[</span></span>
<span id="cb4-39"><a href="#cb4-39" aria-hidden="true"></a>            <span class="st">&#39;secret&#39;</span> =&gt; <span class="kw">$secret_key</span><span class="ot">,</span></span>
<span id="cb4-40"><a href="#cb4-40" aria-hidden="true"></a>            <span class="st">&#39;response&#39;</span> =&gt; <span class="kw">$recaptcha</span><span class="ot">,</span></span>
<span id="cb4-41"><a href="#cb4-41" aria-hidden="true"></a>            <span class="st">&#39;remoteip&#39;</span> =&gt; <span class="kw">$_SERVER</span><span class="ot">[</span><span class="st">&#39;REMOTE_ADDR&#39;</span><span class="ot">]</span></span>
<span id="cb4-42"><a href="#cb4-42" aria-hidden="true"></a>        <span class="ot">]</span></span>
<span id="cb4-43"><a href="#cb4-43" aria-hidden="true"></a>    <span class="ot">]);</span></span>
<span id="cb4-44"><a href="#cb4-44" aria-hidden="true"></a></span>
<span id="cb4-45"><a href="#cb4-45" aria-hidden="true"></a>    <span class="kw">$response_body</span> = <span class="fu">json_decode</span><span class="ot">(</span>wp_remote_retrieve_body<span class="ot">(</span><span class="kw">$response</span><span class="ot">));</span></span>
<span id="cb4-46"><a href="#cb4-46" aria-hidden="true"></a></span>
<span id="cb4-47"><a href="#cb4-47" aria-hidden="true"></a>    <span class="kw">if</span> <span class="ot">(</span>!<span class="kw">$response_body</span>-&gt;success || <span class="kw">$response_body</span>-&gt;score &lt; <span class="fl">0.5</span><span class="ot">)</span> {</span>
<span id="cb4-48"><a href="#cb4-48" aria-hidden="true"></a>        <span class="kw">return</span> <span class="kw">new</span> WP_Error<span class="ot">(</span><span class="st">&#39;captcha_failed&#39;</span><span class="ot">,</span> <span class="st">&#39;reCAPTCHA verification failed.&#39;</span><span class="ot">);</span></span>
<span id="cb4-49"><a href="#cb4-49" aria-hidden="true"></a>    }</span>
<span id="cb4-50"><a href="#cb4-50" aria-hidden="true"></a></span>
<span id="cb4-51"><a href="#cb4-51" aria-hidden="true"></a>    <span class="kw">return</span> <span class="kw">$user</span><span class="ot">;</span></span>
<span id="cb4-52"><a href="#cb4-52" aria-hidden="true"></a>}</span></code></pre>
</div>
<h2 id="layer-3-change-login-url">Layer 3: Change Login URL</h2>
<h3 id="using-wps-hide-login-plugin">Using WPS Hide Login Plugin</h3>
<div class="sourceCode" id="cb5">
<pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true"></a><span class="ex">wp</span> plugin install wps-hide-login --activate</span></code></pre>
</div>
<p><strong>Settings:</strong> Change /wp-login.php to /my-secure-login</p>
<p><strong>Manual Method (via .htaccess):</strong></p>
<div class="sourceCode" id="cb6">
<pre class="sourceCode apache"><code class="sourceCode apache"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true"></a><span class="co"># Redirect wp-login.php to custom URL</span></span>
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true"></a><span class="ex">RewriteEngine</span><span class="ch"> </span><span class="kw">On</span></span>
<span id="cb6-3"><a href="#cb6-3" aria-hidden="true"></a>RewriteCond<span class="st"> %{REQUEST_URI} ^/wp-login\.php</span></span>
<span id="cb6-4"><a href="#cb6-4" aria-hidden="true"></a>RewriteCond<span class="st"> %{QUERY_STRING} !^action=logout</span></span>
<span id="cb6-5"><a href="#cb6-5" aria-hidden="true"></a>RewriteCond<span class="st"> %{QUERY_STRING} !^action=rp</span></span>
<span id="cb6-6"><a href="#cb6-6" aria-hidden="true"></a>RewriteCond<span class="st"> %{QUERY_STRING} !^action=register</span></span>
<span id="cb6-7"><a href="#cb6-7" aria-hidden="true"></a>RewriteRule<span class="st"> ^(.*)$ /custom-login-url? [R=301,L]</span></span></code></pre>
</div>
<p><strong>Caution:</strong> Remember your custom URL. Losing it locks you out.</p>
<h2 id="layer-4-ip-whitelisting">Layer 4: IP Whitelisting</h2>
<h3 id="restrict-wp-admin-by-ip">Restrict wp-admin by IP</h3>
<div class="sourceCode" id="cb7">
<pre class="sourceCode apache"><code class="sourceCode apache"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true"></a><span class="co"># In wp-admin/.htaccess</span></span>
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true"></a><span class="fu">&lt;Files</span><span class="at"> admin-ajax.php</span><span class="fu">&gt;</span></span>
<span id="cb7-3"><a href="#cb7-3" aria-hidden="true"></a>    <span class="ex">Order</span><span class="ch"> </span><span class="kw">allow,deny</span></span>
<span id="cb7-4"><a href="#cb7-4" aria-hidden="true"></a>    Allow<span class="st"> from all</span></span>
<span id="cb7-5"><a href="#cb7-5" aria-hidden="true"></a>    <span class="ex">Satisfy</span><span class="ch"> </span><span class="kw">any</span></span>
<span id="cb7-6"><a href="#cb7-6" aria-hidden="true"></a><span class="fu">&lt;/Files&gt;</span></span>
<span id="cb7-7"><a href="#cb7-7" aria-hidden="true"></a></span>
<span id="cb7-8"><a href="#cb7-8" aria-hidden="true"></a><span class="co"># Block all other wp-admin access except your IP</span></span>
<span id="cb7-9"><a href="#cb7-9" aria-hidden="true"></a><span class="ex">Order</span><span class="ch"> </span><span class="kw">deny,allow</span></span>
<span id="cb7-10"><a href="#cb7-10" aria-hidden="true"></a>Deny<span class="st"> from all</span></span>
<span id="cb7-11"><a href="#cb7-11" aria-hidden="true"></a>Allow<span class="st"> from 123.456.789.0</span></span>
<span id="cb7-12"><a href="#cb7-12" aria-hidden="true"></a>Allow<span class="st"> from 987.654.321.0</span></span></code></pre>
</div>
<p><strong>For Nginx:</strong></p>
<pre class="nginx"><code>location ~* /wp-admin/ {
    allow 123.456.789.0;
    deny all;
}</code></pre>
<p><strong>Dynamic IP Solution (for VPN/mobile users):</strong></p>
<div class="sourceCode" id="cb9">
<pre class="sourceCode php"><code class="sourceCode php"><span id="cb9-1"><a href="#cb9-1" aria-hidden="true"></a><span class="co">// In functions.php - Email-based IP whitelisting</span></span>
<span id="cb9-2"><a href="#cb9-2" aria-hidden="true"></a>add_action<span class="ot">(</span><span class="st">&#39;wp_login_failed&#39;</span><span class="ot">,</span> <span class="st">&#39;email_whitelist_request&#39;</span><span class="ot">);</span></span>
<span id="cb9-3"><a href="#cb9-3" aria-hidden="true"></a></span>
<span id="cb9-4"><a href="#cb9-4" aria-hidden="true"></a><span class="kw">function</span> email_whitelist_request<span class="ot">(</span><span class="kw">$username</span><span class="ot">)</span> {</span>
<span id="cb9-5"><a href="#cb9-5" aria-hidden="true"></a>    <span class="kw">$ip</span> = <span class="kw">$_SERVER</span><span class="ot">[</span><span class="st">&#39;REMOTE_ADDR&#39;</span><span class="ot">];</span></span>
<span id="cb9-6"><a href="#cb9-6" aria-hidden="true"></a>    <span class="kw">$whitelist</span> = get_option<span class="ot">(</span><span class="st">&#39;ip_whitelist&#39;</span><span class="ot">,</span> <span class="ot">[]);</span></span>
<span id="cb9-7"><a href="#cb9-7" aria-hidden="true"></a></span>
<span id="cb9-8"><a href="#cb9-8" aria-hidden="true"></a>    <span class="kw">if</span> <span class="ot">(</span>!<span class="fu">in_array</span><span class="ot">(</span><span class="kw">$ip</span><span class="ot">,</span> <span class="kw">$whitelist</span><span class="ot">))</span> {</span>
<span id="cb9-9"><a href="#cb9-9" aria-hidden="true"></a>        <span class="co">// Send email to admin with &quot;approve&quot; link</span></span>
<span id="cb9-10"><a href="#cb9-10" aria-hidden="true"></a>        <span class="kw">$approve_url</span> = admin_url<span class="ot">(</span><span class="st">&#39;admin.php?action=approve_ip&amp;ip=&#39;</span> . <span class="kw">$ip</span><span class="ot">);</span></span>
<span id="cb9-11"><a href="#cb9-11" aria-hidden="true"></a>        wp_mail<span class="ot">(</span></span>
<span id="cb9-12"><a href="#cb9-12" aria-hidden="true"></a>            get_option<span class="ot">(</span><span class="st">&#39;admin_email&#39;</span><span class="ot">),</span></span>
<span id="cb9-13"><a href="#cb9-13" aria-hidden="true"></a>            <span class="st">&#39;New IP Login Attempt&#39;</span><span class="ot">,</span></span>
<span id="cb9-14"><a href="#cb9-14" aria-hidden="true"></a>            <span class="st">&quot;Approve IP </span><span class="kw">$ip</span><span class="st">: </span><span class="kw">$approve_url</span><span class="st">&quot;</span></span>
<span id="cb9-15"><a href="#cb9-15" aria-hidden="true"></a>        <span class="ot">);</span></span>
<span id="cb9-16"><a href="#cb9-16" aria-hidden="true"></a>    }</span>
<span id="cb9-17"><a href="#cb9-17" aria-hidden="true"></a>}</span></code></pre>
</div>
<h2 id="layer-5-wordpress-firewall">Layer 5: WordPress Firewall</h2>
<h3 id="wordfence-configuration">Wordfence Configuration</h3>
<div class="sourceCode" id="cb10">
<pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb10-1"><a href="#cb10-1" aria-hidden="true"></a><span class="ex">wp</span> plugin install wordfence --activate</span></code></pre>
</div>
<p><strong>Essential Settings:</strong></p>
<ol type="1">
<li>
<p><strong>Enable Extended Protection</strong> (premium feature)</p>
</li>
<li>
<p><strong>Brute Force Protection:</strong></p>
<ul>
<li>Enable login page CAPTCHA</li>
<li>Immediately block invalid usernames</li>
<li>Lock out after 5 failed logins</li>
</ul>
</li>
<li>
<p><strong>Advanced Blocking:</strong></p>
<ul>
<li>Block attackers from specific countries</li>
<li>Throttle login attempts</li>
<li>Block known malicious IPs</li>
</ul>
</li>
</ol>
<p><strong>Rate Limiting Example:</strong></p>
<div class="sourceCode" id="cb11">
<pre class="sourceCode php"><code class="sourceCode php"><span id="cb11-1"><a href="#cb11-1" aria-hidden="true"></a><span class="co">// Wordfence alternative - manual rate limiting</span></span>
<span id="cb11-2"><a href="#cb11-2" aria-hidden="true"></a>add_action<span class="ot">(</span><span class="st">&#39;login_form&#39;</span><span class="ot">,</span> <span class="st">&#39;add_login_delay&#39;</span><span class="ot">);</span></span>
<span id="cb11-3"><a href="#cb11-3" aria-hidden="true"></a></span>
<span id="cb11-4"><a href="#cb11-4" aria-hidden="true"></a><span class="kw">function</span> add_login_delay<span class="ot">()</span> {</span>
<span id="cb11-5"><a href="#cb11-5" aria-hidden="true"></a>    <span class="kw">$ip</span> = <span class="kw">$_SERVER</span><span class="ot">[</span><span class="st">&#39;REMOTE_ADDR&#39;</span><span class="ot">];</span></span>
<span id="cb11-6"><a href="#cb11-6" aria-hidden="true"></a>    <span class="kw">$last_attempt</span> = get_transient<span class="ot">(</span><span class="st">&#39;last_login_attempt_&#39;</span> . <span class="kw">$ip</span><span class="ot">);</span></span>
<span id="cb11-7"><a href="#cb11-7" aria-hidden="true"></a></span>
<span id="cb11-8"><a href="#cb11-8" aria-hidden="true"></a>    <span class="kw">if</span> <span class="ot">(</span><span class="kw">$last_attempt</span> &amp;&amp; <span class="ot">(</span><span class="fu">time</span><span class="ot">()</span> - <span class="kw">$last_attempt</span><span class="ot">)</span> &lt; <span class="dv">3</span><span class="ot">)</span> {</span>
<span id="cb11-9"><a href="#cb11-9" aria-hidden="true"></a>        <span class="fu">sleep</span><span class="ot">(</span><span class="dv">3</span><span class="ot">);</span> <span class="co">// Force 3-second delay between attempts</span></span>
<span id="cb11-10"><a href="#cb11-10" aria-hidden="true"></a>    }</span>
<span id="cb11-11"><a href="#cb11-11" aria-hidden="true"></a></span>
<span id="cb11-12"><a href="#cb11-12" aria-hidden="true"></a>    set_transient<span class="ot">(</span><span class="st">&#39;last_login_attempt_&#39;</span> . <span class="kw">$ip</span><span class="ot">,</span> <span class="fu">time</span><span class="ot">(),</span> <span class="kw">MINUTE_IN_SECONDS</span><span class="ot">);</span></span>
<span id="cb11-13"><a href="#cb11-13" aria-hidden="true"></a>}</span></code></pre>
</div>
<h2 id="layer-6-cloudflare-protection">Layer 6: Cloudflare Protection</h2>
<h3 id="enable-cloudflare-firewall-rules">Enable Cloudflare Firewall Rules</h3>
<ol type="1">
<li>Sign up for Cloudflare (free plan works)</li>
<li>Add your domain</li>
<li>Update nameservers</li>
<li>Enable “Under Attack Mode” during active brute force</li>
</ol>
<p><strong>Firewall Rule:</strong></p>
<pre><code>(http.request.uri.path contains &quot;/wp-login.php&quot;) and
(not ip.geoip.country in {&quot;US&quot; &quot;CA&quot; &quot;GB&quot;})</code></pre>
<p><strong>This blocks non-US/CA/GB traffic to login page.</strong></p>
<h2 id="layer-7-two-factor-authentication">Layer 7: Two-Factor Authentication</h2>
<p>Combine 2FA with login limits for ultimate protection:</p>
<div class="sourceCode" id="cb13">
<pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb13-1"><a href="#cb13-1" aria-hidden="true"></a><span class="ex">wp</span> plugin install two-factor --activate</span></code></pre>
</div>
<p>Even if attackers guess passwords, they can’t login without the second factor.</p>
<h2 id="layer-8-disable-xml-rpc">Layer 8: Disable XML-RPC</h2>
<p>XML-RPC can be used for brute force attacks:</p>
<div class="sourceCode" id="cb14">
<pre class="sourceCode apache"><code class="sourceCode apache"><span id="cb14-1"><a href="#cb14-1" aria-hidden="true"></a><span class="co"># In .htaccess</span></span>
<span id="cb14-2"><a href="#cb14-2" aria-hidden="true"></a><span class="fu">&lt;Files</span><span class="at"> xmlrpc.php</span><span class="fu">&gt;</span></span>
<span id="cb14-3"><a href="#cb14-3" aria-hidden="true"></a>    <span class="ex">Order</span><span class="ch"> </span><span class="kw">deny,allow</span></span>
<span id="cb14-4"><a href="#cb14-4" aria-hidden="true"></a>    Deny<span class="st"> from all</span></span>
<span id="cb14-5"><a href="#cb14-5" aria-hidden="true"></a><span class="fu">&lt;/Files&gt;</span></span></code></pre>
</div>
<p><strong>Or via plugin code:</strong></p>
<div class="sourceCode" id="cb15">
<pre class="sourceCode php"><code class="sourceCode php"><span id="cb15-1"><a href="#cb15-1" aria-hidden="true"></a><span class="co">// Completely disable XML-RPC</span></span>
<span id="cb15-2"><a href="#cb15-2" aria-hidden="true"></a>add_filter<span class="ot">(</span><span class="st">&#39;xmlrpc_enabled&#39;</span><span class="ot">,</span> <span class="st">&#39;__return_false&#39;</span><span class="ot">);</span></span>
<span id="cb15-3"><a href="#cb15-3" aria-hidden="true"></a></span>
<span id="cb15-4"><a href="#cb15-4" aria-hidden="true"></a><span class="co">// Or disable only certain methods</span></span>
<span id="cb15-5"><a href="#cb15-5" aria-hidden="true"></a>add_filter<span class="ot">(</span><span class="st">&#39;xmlrpc_methods&#39;</span><span class="ot">,</span> <span class="st">&#39;disable_xmlrpc_methods&#39;</span><span class="ot">);</span></span>
<span id="cb15-6"><a href="#cb15-6" aria-hidden="true"></a></span>
<span id="cb15-7"><a href="#cb15-7" aria-hidden="true"></a><span class="kw">function</span> disable_xmlrpc_methods<span class="ot">(</span><span class="kw">$methods</span><span class="ot">)</span> {</span>
<span id="cb15-8"><a href="#cb15-8" aria-hidden="true"></a>    <span class="kw">unset</span><span class="ot">(</span><span class="kw">$methods</span><span class="ot">[</span><span class="st">&#39;wp.getUsersBlogs&#39;</span><span class="ot">]);</span></span>
<span id="cb15-9"><a href="#cb15-9" aria-hidden="true"></a>    <span class="kw">unset</span><span class="ot">(</span><span class="kw">$methods</span><span class="ot">[</span><span class="st">&#39;system.multicall&#39;</span><span class="ot">]);</span></span>
<span id="cb15-10"><a href="#cb15-10" aria-hidden="true"></a>    <span class="kw">unset</span><span class="ot">(</span><span class="kw">$methods</span><span class="ot">[</span><span class="st">&#39;system.listMethods&#39;</span><span class="ot">]);</span></span>
<span id="cb15-11"><a href="#cb15-11" aria-hidden="true"></a>    <span class="kw">return</span> <span class="kw">$methods</span><span class="ot">;</span></span>
<span id="cb15-12"><a href="#cb15-12" aria-hidden="true"></a>}</span></code></pre>
</div>
<h2 id="layer-9-server-level-protection-fail2ban">Layer 9: Server-Level Protection (Fail2Ban)</h2>
<h3 id="configure-fail2ban-for-wordpress">Configure Fail2Ban for WordPress</h3>
<div class="sourceCode" id="cb16">
<pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb16-1"><a href="#cb16-1" aria-hidden="true"></a><span class="co"># Install Fail2Ban (Ubuntu/Debian)</span></span>
<span id="cb16-2"><a href="#cb16-2" aria-hidden="true"></a><span class="fu">sudo</span> apt-get install fail2ban</span>
<span id="cb16-3"><a href="#cb16-3" aria-hidden="true"></a></span>
<span id="cb16-4"><a href="#cb16-4" aria-hidden="true"></a><span class="co"># Create WordPress filter</span></span>
<span id="cb16-5"><a href="#cb16-5" aria-hidden="true"></a><span class="fu">sudo</span> nano /etc/fail2ban/filter.d/wordpress.conf</span></code></pre>
</div>
<p><strong>Filter Content:</strong></p>
<div class="sourceCode" id="cb17">
<pre class="sourceCode ini"><code class="sourceCode ini"><span id="cb17-1"><a href="#cb17-1" aria-hidden="true"></a><span class="kw">[Definition]</span></span>
<span id="cb17-2"><a href="#cb17-2" aria-hidden="true"></a><span class="dt">failregex </span><span class="ot">=</span><span class="st"> ^&lt;HOST&gt; .* &quot;POST /wp-login.php</span></span>
<span id="cb17-3"><a href="#cb17-3" aria-hidden="true"></a><span class="dt">            ^&lt;HOST&gt; .* &quot;POST /xmlrpc.php</span></span>
<span id="cb17-4"><a href="#cb17-4" aria-hidden="true"></a><span class="dt">ignoreregex </span><span class="ot">=</span></span></code></pre>
</div>
<p><strong>Jail Configuration:</strong></p>
<div class="sourceCode" id="cb18">
<pre class="sourceCode ini"><code class="sourceCode ini"><span id="cb18-1"><a href="#cb18-1" aria-hidden="true"></a><span class="co"># In /etc/fail2ban/jail.local</span></span>
<span id="cb18-2"><a href="#cb18-2" aria-hidden="true"></a><span class="kw">[wordpress]</span></span>
<span id="cb18-3"><a href="#cb18-3" aria-hidden="true"></a><span class="dt">enabled </span><span class="ot">=</span><span class="st"> </span><span class="kw">true</span></span>
<span id="cb18-4"><a href="#cb18-4" aria-hidden="true"></a><span class="dt">port </span><span class="ot">=</span><span class="st"> http,https</span></span>
<span id="cb18-5"><a href="#cb18-5" aria-hidden="true"></a><span class="dt">filter </span><span class="ot">=</span><span class="st"> wordpress</span></span>
<span id="cb18-6"><a href="#cb18-6" aria-hidden="true"></a><span class="dt">logpath </span><span class="ot">=</span><span class="st"> /var/log/apache2/access.log</span></span>
<span id="cb18-7"><a href="#cb18-7" aria-hidden="true"></a><span class="dt">maxretry </span><span class="ot">=</span><span class="st"> </span><span class="dv">5</span></span>
<span id="cb18-8"><a href="#cb18-8" aria-hidden="true"></a><span class="dt">bantime </span><span class="ot">=</span><span class="st"> </span><span class="dv">3600</span></span>
<span id="cb18-9"><a href="#cb18-9" aria-hidden="true"></a><span class="dt">findtime </span><span class="ot">=</span><span class="st"> </span><span class="dv">600</span></span></code></pre>
</div>
<p>Restart Fail2Ban:</p>
<div class="sourceCode" id="cb19">
<pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb19-1"><a href="#cb19-1" aria-hidden="true"></a><span class="fu">sudo</span> systemctl restart fail2ban</span></code></pre>
</div>
<h2 id="monitoring-and-alerts">Monitoring and Alerts</h2>
<h3 id="email-notifications">Email Notifications</h3>
<div class="sourceCode" id="cb20">
<pre class="sourceCode php"><code class="sourceCode php"><span id="cb20-1"><a href="#cb20-1" aria-hidden="true"></a><span class="co">// Email admin on failed logins</span></span>
<span id="cb20-2"><a href="#cb20-2" aria-hidden="true"></a>add_action<span class="ot">(</span><span class="st">&#39;wp_login_failed&#39;</span><span class="ot">,</span> <span class="st">&#39;notify_failed_login&#39;</span><span class="ot">);</span></span>
<span id="cb20-3"><a href="#cb20-3" aria-hidden="true"></a></span>
<span id="cb20-4"><a href="#cb20-4" aria-hidden="true"></a><span class="kw">function</span> notify_failed_login<span class="ot">(</span><span class="kw">$username</span><span class="ot">)</span> {</span>
<span id="cb20-5"><a href="#cb20-5" aria-hidden="true"></a>    <span class="kw">$ip</span> = <span class="kw">$_SERVER</span><span class="ot">[</span><span class="st">&#39;REMOTE_ADDR&#39;</span><span class="ot">];</span></span>
<span id="cb20-6"><a href="#cb20-6" aria-hidden="true"></a>    <span class="kw">$time</span> = current_time<span class="ot">(</span><span class="st">&#39;mysql&#39;</span><span class="ot">);</span></span>
<span id="cb20-7"><a href="#cb20-7" aria-hidden="true"></a></span>
<span id="cb20-8"><a href="#cb20-8" aria-hidden="true"></a>    wp_mail<span class="ot">(</span></span>
<span id="cb20-9"><a href="#cb20-9" aria-hidden="true"></a>        get_option<span class="ot">(</span><span class="st">&#39;admin_email&#39;</span><span class="ot">),</span></span>
<span id="cb20-10"><a href="#cb20-10" aria-hidden="true"></a>        <span class="st">&#39;Failed Login Attempt&#39;</span><span class="ot">,</span></span>
<span id="cb20-11"><a href="#cb20-11" aria-hidden="true"></a>        <span class="st">&quot;Failed login for username: </span><span class="kw">$username\n</span><span class="st">IP: </span><span class="kw">$ip\n</span><span class="st">Time: </span><span class="kw">$time</span><span class="st">&quot;</span></span>
<span id="cb20-12"><a href="#cb20-12" aria-hidden="true"></a>    <span class="ot">);</span></span>
<span id="cb20-13"><a href="#cb20-13" aria-hidden="true"></a>}</span></code></pre>
</div>
<h3 id="log-analysis">Log Analysis</h3>
<div class="sourceCode" id="cb21">
<pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb21-1"><a href="#cb21-1" aria-hidden="true"></a><span class="co"># View recent failed logins (Apache)</span></span>
<span id="cb21-2"><a href="#cb21-2" aria-hidden="true"></a><span class="fu">grep</span> <span class="st">&quot;wp-login.php&quot;</span> /var/log/apache2/access.log <span class="kw">|</span> <span class="fu">grep</span> <span class="st">&quot;POST&quot;</span> <span class="kw">|</span> <span class="fu">tail</span> -50</span>
<span id="cb21-3"><a href="#cb21-3" aria-hidden="true"></a></span>
<span id="cb21-4"><a href="#cb21-4" aria-hidden="true"></a><span class="co"># Count attempts by IP</span></span>
<span id="cb21-5"><a href="#cb21-5" aria-hidden="true"></a><span class="fu">awk</span> <span class="st">&#39;{print $1}&#39;</span> /var/log/apache2/access.log <span class="kw">|</span> <span class="fu">grep</span> -v <span class="st">&quot;^$&quot;</span> <span class="kw">|</span> <span class="fu">sort</span> <span class="kw">|</span> <span class="fu">uniq</span> -c <span class="kw">|</span> <span class="fu">sort</span> -rn <span class="kw">|</span> <span class="fu">head</span> -20</span></code></pre>
</div>
<h2 id="testing-your-protection">Testing Your Protection</h2>
<h3 id="safe-simulation">Safe Simulation</h3>
<ol type="1">
<li>Use incognito browser</li>
<li>Attempt 5-6 failed logins</li>
<li>Verify lockout occurs</li>
<li>Check email notifications</li>
<li>Confirm CAPTCHA appears (if configured)</li>
<li>Test IP whitelist (from different IP)</li>
</ol>
<p><strong>Automated Test:</strong></p>
<div class="sourceCode" id="cb22">
<pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb22-1"><a href="#cb22-1" aria-hidden="true"></a><span class="co"># Test with curl (safely)</span></span>
<span id="cb22-2"><a href="#cb22-2" aria-hidden="true"></a><span class="kw">for</span> <span class="ex">i</span> in <span class="dt">{1..6}</span><span class="kw">;</span> <span class="kw">do</span></span>
<span id="cb22-3"><a href="#cb22-3" aria-hidden="true"></a>    <span class="ex">curl</span> -X POST https://yoursite.com/wp-login.php <span class="kw">\</span></span>
<span id="cb22-4"><a href="#cb22-4" aria-hidden="true"></a>    <span class="ex">-d</span> <span class="st">&quot;log=testuser&amp;pwd=wrongpassword&quot;</span></span>
<span id="cb22-5"><a href="#cb22-5" aria-hidden="true"></a>    <span class="fu">sleep</span> 2</span>
<span id="cb22-6"><a href="#cb22-6" aria-hidden="true"></a><span class="kw">done</span></span></code></pre>
</div>
<h2 id="best-practices-summary">Best Practices Summary</h2>
<p>✅ <strong>Do:</strong></p>
<ul>
<li>Limit login attempts (4-5 max)</li>
<li>Add CAPTCHA protection</li>
<li>Use strong, unique passwords</li>
<li>Enable 2FA for all admins</li>
<li>Monitor failed login logs</li>
<li>Update security plugins regularly</li>
</ul>
<p>❌ <strong>Don’t:</strong></p>
<ul>
<li>Use “admin” as username</li>
<li>Allow unlimited login attempts</li>
<li>Ignore failed login notifications</li>
<li>Use same password across accounts</li>
<li>Disable security features for convenience</li>
</ul>
<h2 id="complete-protection-stack">Complete Protection Stack</h2>
<p><strong>Recommended combination:</strong></p>
<ol type="1">
<li><strong>Strong passwords</strong> (20+ characters)</li>
<li><strong>Limit Login Attempts Reloaded</strong> (free)</li>
<li><strong>Google reCAPTCHA v3</strong> (free)</li>
<li><strong>Wordfence</strong> or <strong>Sucuri</strong> (free/premium)</li>
<li><strong>Two-Factor Authentication</strong> (free)</li>
<li><strong>Cloudflare</strong> (free tier sufficient)</li>
<li><strong>Fail2Ban</strong> (server-level, free)</li>
</ol>
<p>This multi-layered approach stops 99.9% of brute force attacks while maintaining usability for legitimate users.</p>
<p>Brute force attacks are preventable. By implementing these protective layers, you transform WordPress login from a vulnerable entry point into a hardened fortress. Start with basic login limits and CAPTCHA, then add additional layers based on your threat level and resources.</p>
<h2 id="external-links">External Links</h2>
<ol type="1">
<li><a href="https://wordpress.org/plugins/limit-login-attempts-reloaded/">Limit Login Attempts Reloaded</a></li>
<li><a href="https://www.google.com/recaptcha/">Google reCAPTCHA</a></li>
<li><a href="https://wordpress.org/plugins/wordfence/">Wordfence Security</a></li>
<li><a href="https://www.cloudflare.com/">Cloudflare</a></li>
<li><a href="https://www.fail2ban.org/">Fail2Ban</a></li>
</ol>
<h2 id="call-to-action">Call to Action</h2>
<p>Secure your site with bulletproof backups! <a href="https://backupcopilotplugin.com/">Backup Copilot Pro</a> offers automated security audits, malware scanning before backups, and instant recovery—try it free!</p>
<p>The post <a href="https://developryplugins.com/how-to-block-brute-force-attacks-on-wordpress-login-pages/">How to Block Brute Force Attacks on WordPress Login Pages</a> appeared first on <a href="https://developryplugins.com">Developry Plugins</a>.</p>
]]></content:encoded>
					
		
		
			</item>
	</channel>
</rss>
