Add keys to wp-config.php
<Files .htaccess>
order allow,deny
deny from all
</Files>
Move wp-config.php to another location and create a new wp-config.php to include it
<?php
define ('ABSPATH ' , dirname (__FILE__ ) . '/ ' );
require_once (ABSPATH . '../path/to/wp-config.php ' );
Disable file editing in wp-config.php
define ('DISALLOW_FILE_EDIT ' , true );
Disable access to wp-includes
# Block wp-includes folder and files
<IfModule mod_rewrite.c>
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]
</IfModule>
Prevent username enumeration
RewriteCond %{QUERY_STRING} author=d
RewriteRule ^ /? [L,R=301]
Options +FollowSymLinks
RewriteEngine On
RewriteCond %{QUERY_STRING} (<|%3C).*script.*(>|%3E) [NC,OR]
RewriteCond %{QUERY_STRING} GLOBALS(=|[|%[0-9A-Z]{0,2}) [OR]
RewriteCond %{QUERY_STRING} _REQUEST(=|[|%[0-9A-Z]{0,2})
RewriteRule ^(.*)$ index.php [F,L]
Limit login attempts if necessary
<?php
/**
* CLASS LIMIT LOGIN ATTEMPTS
* Prevent Mass WordPress Login Attacks by setting locking the system when login fail.
* To be added in functions.php or as an external file.
*/
if ( ! class_exists ( 'Limit_Login_Attempts ' ) ) {
class Limit_Login_Attempts {
var $ failed_login_limit = 3 ; //Number of authentification accepted
var $ lockout_duration = 1800 ; //Stop authentification process for 30 minutes: 60*30 = 1800
var $ transient_name = 'attempted_login ' ; //Transient used
public function __construct () {
add_filter ( 'authenticate ' , array ( $ this , 'check_attempted_login ' ), 30 , 3 );
add_action ( 'wp_login_failed ' , array ( $ this , 'login_failed ' ), 10 , 1 );
}
/**
* Lock login attempts of failed login limit is reached
*/
public function check_attempted_login ( $ user , $ username , $ password ) {
if ( get_transient ( $ this ->transient_name ) ) {
$ datas = get_transient ( $ this ->transient_name );
if ( $ datas ['tried ' ] >= $ this ->failed_login_limit ) {
$ until = get_option ( '_transient_timeout_ ' . $ this ->transient_name );
$ time = $ this ->when ( $ until );
return new WP_Error ( 'too_many_tried ' , sprintf ( __ ( '<strong>ERROR</strong>: You have reached authentification limit, you will be able to try again in %1$s. ' ) , $ time ) );
}
}
return $ user ;
}
/**
* Add transient
*/
public function login_failed ( $ username ) {
if ( get_transient ( $ this ->transient_name ) ) {
$ datas = get_transient ( $ this ->transient_name );
$ datas ['tried ' ]++;
if ( $ datas ['tried ' ] <= $ this ->failed_login_limit )
set_transient ( $ this ->transient_name , $ datas , $ this ->lockout_duration );
} else {
$ datas = array (
'tried ' => 1
);
set_transient ( $ this ->transient_name , $ datas , $ this ->lockout_duration );
}
}
/**
* Return difference between 2 given dates
* @param int $time Date as Unix timestamp
* @return string Return string
*/
private function when ( $ time ) {
if ( ! $ time )
return ;
$ right_now = time ();
$ diff = abs ( $ right_now - $ time );
$ second = 1 ;
$ minute = $ second * 60 ;
$ hour = $ minute * 60 ;
$ day = $ hour * 24 ;
if ( $ diff < $ minute )
return floor ( $ diff / $ second ) . ' secondes ' ;
if ( $ diff < $ minute * 2 )
return "about 1 minute ago " ;
if ( $ diff < $ hour )
return floor ( $ diff / $ minute ) . ' minutes ' ;
if ( $ diff < $ hour * 2 )
return 'about 1 hour ' ;
return floor ( $ diff / $ hour ) . ' hours ' ;
}
}
}
//Enable it:
new Limit_Login_Attempts ();
?>