2.13.1.17. Website hack protection on WordPress
Attention!
Before taking any action create site and database backups.- 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. - Remove all unused themes from the directory
wp-content/themes
and unused plugins from the directorywp-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 directorywp-content/themes/name_themes
orwp-content/plugins/name_plugin
. - More than half of free WordPress themes are infected or vulnerable. If you download premium themes from a resource where they are hosted for free, they are most likely to contain malicious code or spam links.
- 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');
- Move config file
wp-config.php
to the directory above the current one. Filewp-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. - Change the database prefix. This can be done using phpMyAdmin:
- 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`;
- Run the generated queries:
- To make sure the prefix is
wp_
is no longer used, run the query:SELECT * FROM `wpnew1_options` WHERE `option_name` LIKE '%wp_%'
- Manually change the prefix to a new one using the button "Edit":
- Do the same after running the following query:
SELECT * FROM `wpnew1_usermeta` WHERE `meta_key` LIKE '%wp_%'
- The last step is to open the config file
wp-config.php
and change the prefix to a new one:
- Change the default admin login
admin
:- Open it and find in the column
user_login
loginadmin
... Click on "Edit", enter the new administrator login and save the changes: - Change the URL of the admin panel. To do this, use the plugin Protect Your Admin:
- Install the plugin, open the plugin menu, change the URL and click "Save":
- In chapter "Settings → Permalinks" install the option "Record name":
Now the admin panel will be available at an address like
example.com/wpmyadmin
.
- 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]
- 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>
- Restrict IP access to the admin panel. This recommendation is suitable for those with a static IP address. In file
.htaccess
in the root of the site add 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. - A small firewall for the site. These rules can slow down the work of the site, since every request coming to the site will be analyzed with their help. If you notice a significant decrease in the speed of the site, you should not use these rules. Try using the plugin 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>