2.14.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
. - Более половины бесплатных тем WordPress заражены or уязвимы. Если вы скачиваете премиум-themes с ресурса, где они размещены бесплатно, с большой вероятностью они содержат вредоносный код or спам-ссылки.
- 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:
- Execute SQL Query
SHOW TABLES
: - 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
:- Signin in phpMyAdmin, select base and find table
prefix_users
: - Open it and find in the column
user_login
loginadmin
... Click on «Edit», впишите новый login администратора и сохраните изменения: - Change the URL of the admin panel. To do this, use the plugin Protect Your Admin:
- Установите плагин, откройте меню plugin, замените URL и нажмите «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
в корневом каталоге сайта добавьте 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. - Небольшой файрвол для сайта. Данные правила могут замедлить работу сайта, так как каждый запрос, поступающий на сайт, будет анализироваться с их помощью. Если вы заметите существенное снижение скорости работы сайта, не следует использовать данные правила. 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>