2.14.1.17. Website hack protection on WordPress

Attention!

Before taking any action create site and database backups.
  1. Update WordPress, themes, and plugins regularly. Currently, the share of WordPress CMS exceeds 30% of all websites in the world. Due to its sheer prevalence, WordPress is a popular target for hackers. Since WordPress is an open source CMS, anyone can access the code to learn and improve it. However, this also means that hackers can study it and find ways to break into websites.
    Every time a vulnerability is discovered, WordPress developers work hard to release an update that fixes the problem. If you are not using the latest version of WordPress, you are using software with known security vulnerabilities.
  2. Remove all unused themes from the directory wp-content/themes and unused plugins from the directory wp-content/plugins... Storing free themes and plugins dramatically increases the likelihood of a site being hacked. If a theme or plugin is inactive, it still allows you to open malicious scripts from the directory wp-content/themes/name_themes or wp-content/plugins/name_plugin.
  3. Более половины бесплатных тем WordPress заражены or уязвимы. Если вы скачиваете премиум-themes с ресурса, где они размещены бесплатно, с большой вероятностью они содержат вредоносный код or спам-ссылки.
  4. Disable the display of the Wordpress version. Attackers will not know the version, which means they will not know the vulnerabilities either. To do this, open the file wp-content/themes/name_themes/functions.php and add the following code after the first line:
    function remove_wordpress_version_number() {
        return '';
    }
    add_filter('the_generator', 'remove_wordpress_version_number');
    function remove_version_from_scripts( $src ) {
       if ( strpos( $src, '?ver=' ) )
           $src = remove_query_arg( 'ver', $src );
       return $src;
    }
    add_filter( 'style_loader_src', 'remove_version_from_scripts');
    add_filter( 'script_loader_src', 'remove_version_from_scripts');
  5. Move config file wp-config.php to the directory above the current one. File wp-config.php contains the basic settings of your site and this is the most important file in root directory of the site. In the current WordPress architecture, the config file is checked with the highest priority. This way, even if it’s stored in one folder above the root directory, WordPress will still be able to see it. You need to move the given file from the directory /home/name_hosting_account/name_site/www/ to catalog /home/name_hosting_account/name_site/. Attention! This recommendation only applies if you use a single subdomain.
  6. Change the database prefix. This can be done using phpMyAdmin:
    1. Execute SQL Query SHOW TABLES:
    2. Copy the resulting list of all tables in the database and create a similar query for each table:
      RENAME TABLE `wp_comments` TO `wpnew1_comments`;
    3. Run the generated queries:
    4. To make sure the prefix is wp_ is no longer used, run the query:
      SELECT * FROM `wpnew1_options` WHERE `option_name` LIKE '%wp_%'
    5. Manually change the prefix to a new one using the button «Edit»:
    6. Do the same after running the following query:
      SELECT * FROM `wpnew1_usermeta` WHERE `meta_key` LIKE '%wp_%'
    7. The last step is to open the config file wp-config.php and change the prefix to a new one:
  7. Change the default admin login admin:
    1. Signin in phpMyAdmin, select base and find table prefix_users:
    2. Open it and find in the column user_login login admin... Click on «Edit», впишите новый login администратора и сохраните изменения:
    3. Change the URL of the admin panel. To do this, use the plugin Protect Your Admin:
      1. Установите плагин, откройте меню plugin, замените URL и нажмите «Save»:
      2. In chapter «Settings → Permalinks» install the option «Record name»:Now the admin panel will be available at an address like example.com/wpmyadmin.
  8. Deny access to the file xmlrpc.php... To do this, in the root directory of the site in the file .htaccess add one of the restriction options:
    # Redirect to local address. The log will contain a 301 response code.
    RewriteRule ^xmlrpc\.php$ "http\:\/\/127\.0\.0\.1\/" [R=301,L]
     
    # Deny access to the file. The log will contain a 403 response code.
    RewriteRule ^xmlrpc.php$ - [F,L]
  9. Disable the execution of PHP files in the downloads directory. This is a common place to download viruses. To prevent the execution of malicious code in the event of a breach, add to the file wp-content/uploads/.htaccess the following code:
    <Files ~ "\.(php)$">
      Order allow,deny
      Deny from all
    </Files>
  10. Restrict IP access to the admin panel. This recommendation is suitable for those with a static IP address. In file .htaccess в корневом каталоге сайта добавьте the following code:
    RewriteEngine on
    RewriteCond %{REQUEST_URI} ^(.*)?wp-admin$ [OR]
    RewriteCond %{REQUEST_URI} ^(.*)?wp-login\.php(.*)$
    RewriteCond %{REMOTE_ADDR} !^127.0.0.1$
    RewriteRule ^(.*)$ - [R=403,L]

    Instead 127.0.0.1 enter your IP address.

  11. Небольшой файрвол для сайта. Данные правила могут замедлить работу сайта, так как каждый запрос, поступающий на сайт, будет анализироваться с их помощью. Если вы заметите существенное снижение скорости работы сайта, не следует использовать данные правила. Instead этого попробуйте воспользоваться плагином Wordfence Security — Firewall & Malware Scan.
    Add firewall code to file .htaccess in the root directory of the site:
    <IfModule mod_rewrite.c> RewriteEngine On # Block XSS RewriteCond%{QUERY_STRING} (\<|%3C).*script.*(\>|%3E) [NC,OR]
    # Block the setting of the PHP GLOBALS variable via the URL RewriteCond%{QUERY_STRING} GLOBALS(=|\[|\%[0-9A-Z]{0,2}) [OR]
    # Block the ability to change the variable _REQUEST via URL RewriteCond%{QUERY_STRING} _REQUEST(=|\[|\%[0-9A-Z]{0,2}) # Block MySQL injection, RFI, base64, etc. RewriteCond%{QUERY_STRING} (javascript:)(.*)(;) [NC,OR]
    RewriteCond %{QUERY_STRING} [a-zA-Z0-9_]=http:// [OR]
    RewriteCond %{QUERY_STRING} [a-zA-Z0-9_]=(\.\.//?)+ [OR]
    RewriteCond %{QUERY_STRING} [a-zA-Z0-9_]=/([a-z0-9_.]//?)+ [NC,OR]
    RewriteCond %{QUERY_STRING} \=PHP[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12} [NC,OR]
    RewriteCond %{QUERY_STRING} (\.\./|\.\.) [OR]
    RewriteCond %{QUERY_STRING} ftp\: [NC,OR]
    RewriteCond %{QUERY_STRING} http\: [NC,OR]
    RewriteCond %{QUERY_STRING} https\: [NC,OR]
    RewriteCond %{QUERY_STRING} \=\|w\| [NC,OR]
    RewriteCond %{QUERY_STRING} ^(.*)/self/(.*)$ [NC,OR]
    RewriteCond %{QUERY_STRING} ^(.*)cPath=http://(.*)$ [NC,OR]
    RewriteCond %{QUERY_STRING} (\<|%3C).*script.*(\>|%3E) [NC,OR]
    RewriteCond %{QUERY_STRING} (<|%3C)([^s]*s)+cript.*(>|%3E) [NC,OR]
    RewriteCond %{QUERY_STRING} (\<|%3C).*iframe.*(\>|%3E) [NC,OR]
    RewriteCond %{QUERY_STRING} (<|%3C)([^i]*i)+frame.*(>|%3E) [NC,OR]
    RewriteCond %{QUERY_STRING} mosConfig_[a-zA-Z_]{1,21}(=|%3D) [OR]
    RewriteCond %{QUERY_STRING} base64_encode.*\(.*\) [NC,OR]
    RewriteCond %{QUERY_STRING} base64_(en|de)code[^(]*\([^)]*\) [NC,OR]
    RewriteCond %{QUERY_STRING} ^.*(\[|\]|\(|\)|<|>).* [NC,OR]
    RewriteCond %{QUERY_STRING} (NULL|OUTFILE|LOAD_FILE) [OR]
    RewriteCond %{QUERY_STRING} (\./|\./|\./)+(motd|etc|bin) [NC,OR]
    RewriteCond %{QUERY_STRING} (localhost|loopback|127\.0\.0\.1) [NC,OR]
    RewriteCond %{QUERY_STRING} (<|>|'|%0A|%0D|%27|%3C|%3E|%00) [NC,OR]
    RewriteCond %{QUERY_STRING} concat[^\(]*\( [NC,OR]
    RewriteCond %{QUERY_STRING} union([^s]*s)+elect [NC,OR]
    RewriteCond %{QUERY_STRING} union([^a]*a)+ll([^s]*s)+elect [NC,OR]
    RewriteCond %{QUERY_STRING} (;|<|>|'|"|\)|%0A|%0D|%22|%27|%3C|%3E|%00).*(/\*|union|select|insert|drop|delete|update|cast|create|char|convert|alter|declare|order|script|set|md5|benchmark|encode) [NC,OR]
    RewriteCond %{QUERY_STRING} (\|\.\.\.|\.\./|~|`|<|>|\|) [NC,OR]
    RewriteCond %{QUERY_STRING} (boot\.ini|etc/passwd|self/environ) [NC,OR]
    RewriteCond %{QUERY_STRING} (thumbs?(_editor|open)?|tim(thumb)?)\.php [NC,OR]
    RewriteCond %{QUERY_STRING} (sp_executesql) [NC]
    RewriteCond %{QUERY_STRING} (eval\() [NC,OR]
    RewriteCond %{QUERY_STRING} ([a-z0-9]{2000,}) [NC,OR]
    RewriteRule ^(.*)$ - [F,L]
    # Block known Shell RewriteEngine on RewriteCond%{REQUEST_URI} .*((php|my)?shell|remview.*|phpremoteview.*|sshphp.*|pcom|nstview.*|c99|r57|webadmin.*|phpget.*|phpwriter.*|fileditor.*|locus7.*|storm7.*).(p?s?x?htm?l?|txt|aspx?|cfml?|cgi|pl|php[3-9]{0,1}|jsp?|sql|xml) [NC,OR]
    RewriteCond %{REQUEST_METHOD} (GET|POST) [NC]
    RewriteCond %{QUERY_STRING} ^(.*)=(/|%2F)(h|%68|%48)(o|%6F|%4F)(m|%6D|%4D)(e|%65|%45)(.+)?(/|%2F)(.*)(/|%2F)(.*)$ [OR]
    RewriteCond %{QUERY_STRING} ^work_dir=.*$ [OR]
    RewriteCond %{QUERY_STRING} ^command=.*&output.*$ [OR]
    RewriteCond %{QUERY_STRING} ^nts_[a-z0-9_]{0,10}=.*$ [OR]
    RewriteCond %{QUERY_STRING} ^c=(t|setup|codes)$ [OR]
    RewriteCond %{QUERY_STRING} ^act=((about|cmd|selfremove|chbd|trojan|backc|massbrowsersploit|exploits|grablogins|upload.*)|((chmod|f)&f=.*))$ [OR]
    RewriteCond %{QUERY_STRING} ^act=(ls|search|fsbuff|encoder|tools|processes|ftpquickbrute|security|sql|eval|update|feedback|cmd|gofile|mkfile)&d=.*$ [OR]
    RewriteCond %{QUERY_STRING} ^&?c=(l?v?i?&d=|v&fnot=|setup&ref=|l&r=|d&d=|tree&d|t&d=|e&d=|i&d=|codes|md5crack).*$ [OR]
    RewriteCond %{QUERY_STRING} ^(.*)([-_a-z]{1,15})=(chmod|chdir|mkdir|rmdir|clear|whoami|uname|unzip|gzip|gunzip|grep|more|umask|telnet|ssh|ftp|head|tail|which|mkmode|touch|logname|edit_file|search_text|find_text|php_eval|download_file|ftp_file_down|ftp_file_up|ftp_brute|mail_file|mysql|mysql_dump|db_query)([^a-zA-Z0-9].+)*$ [OR]
    RewriteCond %{QUERY_STRING} ^(.*)(wget|shell_exec|passthru|system|exec|popen|proc_open)(.*)$
    RewriteRule .* - [F]
    </IfModule>
Content