{"id":2389,"date":"2015-05-20T10:51:00","date_gmt":"2015-05-20T07:51:00","guid":{"rendered":"http:\/\/dima.fi\/blog\/?p=2389"},"modified":"2026-01-10T22:58:06","modified_gmt":"2026-01-10T20:58:06","slug":"wordpress-brute-force-attack","status":"publish","type":"post","link":"https:\/\/dima.fi\/blog\/wordpress-brute-force-attack\/","title":{"rendered":"Prevent WordPress wp-login.php brute force attack"},"content":{"rendered":"\n<p>I&#8217;m maintaining a lot of WordPress based sites. And almost daily there is some brute force attack on one of them. The target of these attacks is&nbsp;<em>wp-login.php<\/em>&nbsp;file. There is a lot of solutions to protect this file by limiting access to it using a separate password or manually adding allowed IP address. And changing them all the time is not an option for me.<\/p>\n\n\n\n<p>So how I solved this? By automagisation! \ud83d\ude09<br>Main point is to modify&nbsp;<em>.htaccess<\/em>&nbsp;file to have access rules like:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"apacheconf\" class=\"language-apacheconf\">&lt;Files wp-login.php>\n   Order deny,allow\n   Deny from all\n   Allow from 123.123.123.123\n&lt;\/Files><\/code><\/pre>\n\n\n\n<p>This rule denies access from all and allows from ip 123.123.123.123.<\/p>\n\n\n\n<p>But we need to change IP automatically wherever we are. My solution is to use a PHP script that checks my current IP and changes it to&nbsp;<em>.htaccess<\/em>&nbsp;file. And by adding a little bit of magic I can access&nbsp;<em>wp-login.php<\/em>&nbsp;with only one click! How?<\/p>\n\n\n\n<p>Like this:<\/p>\n\n\n\n<ol class=\"wp-block-list\"><li>I&#8217;m opening&nbsp;<em>my-wordpress-site.com\/magical-login.php<\/em>&nbsp;url<\/li><li><em>magical-login.php<\/em>&nbsp;checks my current IP and changes it to the access rule<\/li><li><em>magical-login.php<\/em>&nbsp;redirects me to&nbsp;<em>wp-login.php<\/em>, which now accessible for me<\/li><\/ol>\n\n\n\n<p>And of course nobody knows that&nbsp;<em>magical-login.php<\/em>&nbsp;file exists. I can change the filename to whatever I want.<\/p>\n\n\n\n<p>You probably want to know what does this&nbsp;<em>magical-login.php<\/em>&nbsp;contain? Here:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code lang=\"php\" class=\"language-php\">&lt;?php \n\n\/\/ reading current content from .htaccess\n$ht = fopen(\".htaccess\", \"r\");\n$content = fread($ht, filesize(\".htaccess\"));\nfclose($ht);\n\n\/\/ removing old access rule for wp-login.php file \n$content = preg_replace(\"\/\\&lt;Files wp-login\\.php\\>.*\\&lt;\\\/Files\\>\\s+\/s\",\"\",$content);\n\n\/\/ checking current ip address\nif (!empty($_SERVER['HTTP_CLIENT_IP'])) $ip = $_SERVER['HTTP_CLIENT_IP'];\nelseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) $ip = $_SERVER['HTTP_X_FORWARDED_FOR'];\nelse $ip = $_SERVER['REMOTE_ADDR'];\n\n\/\/ creating new access rule with new ip address\n$rule = &lt;&lt;&lt; rule\n&lt;Files wp-login.php>\n        Order deny,allow\n        Deny from all\n        Allow from $ip\n&lt;\/Files>\n\nrule;\n\n\/\/ writing new .htaccess content\n$ht = fopen(\".htaccess\", \"w\");\nfwrite($ht, $rule.$content);\nfclose($ht);\n\n\/\/ redirecting to wp-login.php\nheader('Location: wp-login.php');\n\n?><\/code><\/pre>\n\n\n\n<p>Make sure your webserver has write permission to&nbsp;<em>.htaccess<\/em>&nbsp;file.<\/p>\n\n\n\n<p>Just drop your PHP file to the same folder with&nbsp;<em>wp-login.php<\/em>&nbsp;and open it with your browser. It will add access rule to the top of&nbsp;<em>.htaccess<\/em>&nbsp;file and you are done. Next time just forget about&nbsp;<em>wp-login.php<\/em>&nbsp;and use the file you have created.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Prevent hackers from brute force attacking Wordpress&#8217; wp-login.php file<\/p>\n","protected":false},"author":1,"featured_media":2431,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"fifu_image_url":"https:\/\/images.unsplash.com\/photo-1563705883268-eb58ab6f505d?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=1080&fit=max&ixid=eyJhcHBfaWQiOjF9","fifu_image_alt":"Prevent WordPress wp-login.php brute force attack","footnotes":""},"categories":[133],"tags":[162,139,134,161],"class_list":["post-2389","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-web-devs","tag-brute-force","tag-dev","tag-web","tag-wordpress","has-thumbnail"],"_links":{"self":[{"href":"https:\/\/dima.fi\/blog\/wp-json\/wp\/v2\/posts\/2389","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/dima.fi\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/dima.fi\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/dima.fi\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/dima.fi\/blog\/wp-json\/wp\/v2\/comments?post=2389"}],"version-history":[{"count":2,"href":"https:\/\/dima.fi\/blog\/wp-json\/wp\/v2\/posts\/2389\/revisions"}],"predecessor-version":[{"id":2392,"href":"https:\/\/dima.fi\/blog\/wp-json\/wp\/v2\/posts\/2389\/revisions\/2392"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/dima.fi\/blog\/wp-json\/wp\/v2\/media\/2431"}],"wp:attachment":[{"href":"https:\/\/dima.fi\/blog\/wp-json\/wp\/v2\/media?parent=2389"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/dima.fi\/blog\/wp-json\/wp\/v2\/categories?post=2389"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/dima.fi\/blog\/wp-json\/wp\/v2\/tags?post=2389"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}