Leaving your wp-login.php script or wp-admin folder accessible from the internet allows for bruteforcing of your passwords
My way of solving this is by creating a randomly named folder e.g. “asbra” with som php code that sets a cookie which is required by the .htaccess file.
<?php
$admin_cookie_code="329847348597";
setcookie("AsbraSession",$admin_cookie_code,0,"/");
header("Location: ../wp-admin/index.php");
?>
Then paste the following at the bottom of your .htaccess file
###############################
# BEGIN Asbra AB <j@asbra.nu> #
###############################
#
# Cookie based access to administration
#
<IfModule mod_rewrite.c>
RewriteEngine On
# Only allow admin if ASBRA Cookie has been set correctly
RewriteCond %{REQUEST_URI} /wp-login.php
RewriteCond %{HTTP_COOKIE} !AsbraSession=329847348597
RewriteRule .* - [L,F]
RewriteCond %{REQUEST_URI} /wp-admin
RewriteCond %{HTTP_COOKIE} !AsbraSession=329847348597
RewriteRule .* - [L,F]
# Disable WordPress include-only files
RewriteEngine On
RewriteBase /
RewriteRule ^wp-admin/includes/ - [F,L]
RewriteRule !^wp-includes/ - [S=3]
RewriteRule ^wp-includes/[^/]+\.php$ - [F,L]
RewriteRule ^wp-includes/js/tinymce/langs/.+\.php - [F,L]
RewriteRule ^wp-includes/theme-compat/ - [F,L]
# Do we really need the Trace, Delete and Track Request Methods ?
RewriteCond %{REQUEST_METHOD} ^(TRACE|DELETE|TRACK) [NC]
RewriteRule ^(.*)$ - [F,L]
# Block User ID Phishing Requests
RewriteCond %{QUERY_STRING} ^author=([0-9]*)
RewriteRule .* - [L,F]
#RewriteRule .* http://example.com/? [L,R=302]
</IfModule>
#
# And then some extra file/uri security
#
# This stops hackers from trying thousands of passwords in only a few requests
<Files xmlrpc.php>
order allow,deny
deny from all
</Files>
<Files wp-cron.php>
order allow,deny
deny from all
</Files>
<Files wp-links-opml.php>
order allow,deny
deny from all
</Files>
<files ~ "^.*\.([Hh][Tt][Aa])">
order allow,deny
deny from all
</files>
<files wp-config.php>
order allow,deny
deny from all
</files>
# Are you using the REST API?
<files wp-json>
order allow,deny
deny from all
</files>
#
# Set extra headers for clients
#
<IfModule mod_headers.c>
# nosniff - Blocks a request if the requested type is "style" and the MIME type is not "text/css", or "script" and the MIME type is not a JavaScript MIME type.
Header set X-Content-Type-Options nosniff
# Enable the cross-site scripting (XSS) filter in users browser
Header set X-XSS-Protection "1; mode=block"
# Require HTTPS (Be very careful! this is saved in the clients browser for 2 years!)
# Header always set Strict-Transport-Security "max-age=63072000; includeSubdomains;"
# Prevent Fraudulent Iframing
Header set X-Frame-Options "SAMEORIGIN"
# Add your own! Only allow includes from SELF and from CDN (Unsafe inline is needed if wee want inline javascript and CSS)
Header add Content-Security-Policy "style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; font-src 'self' https://fonts.gstatic.com; img-src 'self' data: http://cdn.asbra.nu;"
# Dont give away referer on outgoing links
Header always set Referrer-Policy "same-origin"
# Block client from certain features
Header set Feature-Policy "microphone 'none';camera 'none';geolocation 'self';payment 'none';sync-xhr 'self'"
# Unset headers revealing versions strings
Header unset X-Powered-By
Header unset X-Pingback
Header unset SERVER
</IfModule>
################
# END Asbra AB #
################
We also want to limit the upload folder. Place this .htaccess in your wp-contents/ folder
Order deny,allow Deny from all <Files ~ ".(xml|css|jpe?g|png|gif|js)$"> Allow from all </Files>
And just in case someone gets a hold och your backend, limit their possibility to edit your files by placing the following at the end of wp-config.php
define('DISALLOW_FILE_EDIT', true);
WordPress will install minor updates automatically, to enable all core updates, including minor and major:
define( 'WP_AUTO_UPDATE_CORE', true );
