PDA

View Full Version : Tips to secure Wordpress - Prevent malicious code execution & file modiffication



Fli
04-12-2014, 10:39 PM
Hi, do You know any good tutorials or ways on how to secure/harden/protect wordpress against hacking?

I found and tested following information on how to secure wordpress, these are only veriffied and the best advices filtered out of many that are low or no efficient.

Jiný návod: https://help.wedos.cz/navody/serial/wordpress/12-tipu-pro-lepsi-zabezpeceni-wordpress/

# TIP 0

Backup your site regularly. Imagine that someone delete your website and mysql and you dont have any backup... So make sure Your wordpress website and mysql database (or entire hosting account) is backed up regularly. There are wp plugins that does this automatically (search: wordpress auto backup mysql files plugins). You may check "Script to backup website files and mysql database to the website subfolder (http://internetlifeforum.com/programming-scripting/2557-script-backup-website-files-mysql-database-website-subfolder/)"

# TIP 0.5

Install plugin like https://wordpress.org/plugins/ninjafirewall/
But if you prefer not to install such a plugin, continue reading.

# TIP 1

- disallow listing of files in wordpress directories if there is no index.php or index.html file
- disallow opening .php files directly
- disallow opening include-only files
- disallow opening wp-config.php file
- disallow suspicious/hacking requests

Add following code into .htaccess file (located in same folder as index.php, wp-config.php):


# Disable directory browsing
Options All -Indexes

# disallow opening/executing .php file directly
RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /[^\ ]+\.php($|\ )
RewriteCond %{REQUEST_URI} !wp-comments-post.php
RewriteCond %{REQUEST_URI} !wp-login.php
RewriteRule \.php$ / [F,L]

# Block the include-only 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>

# Disallow executing wp-config file
<files wp-config.php>
Order Allow,Deny
Deny from All
</files>

# htaccess firewall v1.0 | https://github.com/alidbg/htaccess_firewall
<IfModule mod_rewrite.c>
ServerSignature Off
Options -Indexes
RewriteEngine On
ErrorDocument 403 "This request is forbidden by the htaccess firewall <a href=https://github.com/alidbg/htaccess_firewall target=_blank>https://github.com/alidbg/htaccess_firewall</a>"
RewriteCond %{REQUEST_METHOD} ^(HEAD|TRACE|DELETE|TRACK|DEBUG) [NC]
RewriteRule ^(.*)$ - [F]
RewriteCond %{REQUEST_URI} (wp-config\.php|config\.php|bb-config\.php|timthumb\.php|phpthumb\.php|thumb\.php |thumbs\.php|debug\.log) [NC,OR]
RewriteCond %{REQUEST_URI} \.(htaccess|htpasswd|errordocs|logs|po|mo|ini|inc) $ [NC,OR]
RewriteCond %{HTTP_USER_AGENT} (;|<|>|'|"|\)|\(|%0A|%0D|%22|%27|%28|%3C|%3E|%00).*(libwww-perl|wget|python|nikto|curl|scan|java|winhttp|HTTr ack|clshttp|archiver|loader|email|harvest|extract| grab|miner) [NC,OR]
RewriteCond %{HTTP_USER_AGENT} (havij|libwww-perl|wget|python|nikto|curl|scan|java|winhttp|clsh ttp|loader) [NC,OR]
RewriteCond %{HTTP_USER_AGENT} (%0A|%0D|%27|%3C|%3E|%00|%60) [NC,OR]
RewriteCond %{HTTP_REFERER} (%0A|%0D|%27|%3C|%3E|%00) [NC,OR]
RewriteCond %{THE_REQUEST} \?\ HTTP/ [NC,OR]
RewriteCond %{THE_REQUEST} \/\*\ HTTP/ [NC,OR]
RewriteCond %{HTTP_COOKIE} (`|'|"|%22|%0A|%0D|%27|%3C|%28|%3E|%00|%60).*(declare|ch ar|setBAD|cast|convert|delete|drop|exec|eval|inser t|meta|script|select|truncate|update|union|md5|ben chmark|create|alter|order|encode|if|and|orBAD).* [NC,OR]
RewriteCond %{QUERY_STRING} (`|'|"|%22|%0A|%0D|%27|%3C|%28|%3E|%00|%60).*(declare|ch ar|set|cast|convert|delete|drop|exec|eval|insert|m eta|script|select|truncate|update|union|md5|benchm ark|create|alter|order|encode|if|and|or).* [NC,OR]
RewriteCond %{QUERY_STRING} [a-zA-Z0-9_]=http:// [NC,OR]
RewriteCond %{QUERY_STRING} [a-zA-Z0-9_]=(\.\.//?)+ [NC,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} (\.\./|%2e%2e%2f|%2e%2e/|\.\.%2f|%2e\.%2f|%2e\./|\.%2e%2f|\.%2e/) [NC,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).*embed.*(\>|%3E) [NC,OR]
RewriteCond %{QUERY_STRING} (<|%3C)([^e]*e)+mbed.*(>|%3E) [NC,OR]
RewriteCond %{QUERY_STRING} (\<|%3C).*object.*(\>|%3E) [NC,OR]
RewriteCond %{QUERY_STRING} (<|%3C)([^o]*o)+bject.*(>|%3E) [NC,OR]
RewriteCond %{QUERY_STRING} (\<|%3C).*iframe.*(\>|%3E) [NC,OR]
RewriteCond %{QUERY_STRING} (<|%3C)([^i]*i)+frame.*(>|%3E) [NC,OR]
RewriteCond %{QUERY_STRING} base64_encode.*\(.*\) [NC,OR]
RewriteCond %{QUERY_STRING} base64_(en|de)code[^(]*\([^)]*\) [NC,OR]
RewriteCond %{QUERY_STRING} GLOBALS(=|\[|\%[0-9A-Z]{0,2}) [OR]
RewriteCond %{QUERY_STRING} _REQUEST(=|\[|\%[0-9A-Z]{0,2}) [OR]
RewriteCond %{QUERY_STRING} ^.*(\(|\)|<|>|%3c|%3e).* [NC,OR]
RewriteCond %{QUERY_STRING} ^.*(\x00|\x04|\x08|\x0d|\x1b|\x20|\x3c|\x3e|\x7f). * [NC,OR]
RewriteCond %{QUERY_STRING} (NULL|OUTFILE|LOAD_FILE) [OR]
RewriteCond %{QUERY_STRING} (\.{1,}/)+(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|%60) [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} \-[sdcr].*(allow_url_include|allow_url_fopen|safe_mode|dis able_functions|auto_prepend_file) [NC,OR]
RewriteCond %{QUERY_STRING} (;|<|>|'|"|\)|%0A|%0D|%22|%27|%3C|%3E|%00).*(/\*|union|select|insert|drop|delete|update|cast|cre ate|char|convert|alter|declare|order|script|set|md 5|benchmark|encode|and|or|if) [NC,OR]
RewriteCond %{QUERY_STRING} (sp_executesql) [NC]
RewriteRule ^(.*)$ - [F]
</IfModule>
# END htaccess firewall

To restrict admin area only to one/your IP, you can append following code to above mentioned .htaccess file:

# Allow only your IPs (www.myip.ms) to access login page (bots can put load on your server)
<Files wp-login.php>
Order deny,allow
Deny from All
Allow from xxx.xxx.xxx.xxx
Allow from yyy.yyy.yyy.yyy
</Files>
If you see Error 500 on your site, then try to remove some parts of the code you inserted.

# TIP 2

Disallow executing any .php* .htm* and .js files in wp-content directory tree. So if any thief inject an bad .php script (shell,spamming script, ddos script etc), he should not be able to run it (unless he include it into an existing wordpress file). Test that website works properly after adding the rules into /wp-content/.htaccess.



<Files *.php*>
Deny from All
</Files>

#<Files *.js>
#Deny from All
#</Files>

<Files *.htm*>
Deny from All
</Files>

i commented out (#) .js related block, because some plugins or themes fetch .js and php files from wp-content subdirectories, so you can uncomment it but then watch your apache error log after browsing your wordpress website if there are no errors.
In case some plugin is denied to access its file, one can add .htaccess into its directory and allow particular file name like:
<Files includefilename.extesion>
Allow from All
</Files>
[/CODE]

# TIP 3

add following into /wp-includes/.htaccess and no one should execute any file from wp-includes folder in his web browser


RewriteRule ^(wp-includes)\/.*$ ./ [NC,R=301,L]

do NOT add .php DENY FROM ALL into wp-includes or wordpress post editor may stop accepting any text input (more about wp editor issue (http://internetlifeforum.com/wordpress/2775-wordpress-post-editor-edit-article-do-not-show-any-text-do-not-accept-any-text/))

# TIP 4

Disable writing permissions of the Wordpress files/folders (disallow anyone modifying files and adding new files).
After this, wordpress updates will fail, plugin installation will fail, upload will fail. By doing this, you virtually lock wordpress files in its current state disallowing any script to change them.. I tested this and my wordpress frontend and backed worked quite OK.

How to do it? Change permissions for files from 644 to 544 and folder permissions from 755 to 555



r = 4
w = 2
x = 1

7 = r+w+x
6 = r+w
5 = r+x
4= r

Before doing any following commands, backup your files!

option A changed all files and folders permissions to lack write bit (files - 544, folders - 555)
I do it like this from linux command line:

cd /home/myusername/public_html
find . -type f -exec chmod 544 {} \;
find . -type d -exec chmod 555 {} \;
use above commands very carefully, it can damage server if not done in the website directory but done for example from server / path. If its too hard for you to do above change, try placing following line in wp-config.php. It is equivalent to removing the 'edit_themes', 'edit_plugins' and 'edit_files' capabilities of all users: define('DISALLOW_FILE_EDIT', true);
(its only from admin area change prevention, so not sufficing probably)

Option B is to change permissions only for wp-content, wp-includes etc, but why to do it? I think its better to completelly secure site doing above commands (option A) then following ones. (i have experience my site got hacked/malicious scripts uploaded, files modiffied) using method B and C)



cd /home/myusername/public_html
chmod 555 wp-content wp-includes wp-admin
find ./wp-content -type f -print0 | xargs -0 chmod 544
find ./wp-includes -type f -print0 | xargs -0 chmod 544
find ./wp-content -type d -print0 | xargs -0 chmod 555
find ./wp-includes -type d -print0 | xargs -0 chmod 555

option C
if one have many wordpress blogs and need to chmod 555 wp-content, wp-includes, wp-admin, one can do like: find /home/yourusername/public_html -type d -name "wp-content" -o -name "wp-includes" -o -name "wp-admin" -exec chmod 555 {} \;
BUT that would change only these folders permission, not permission of its sub-folders (which is what i think is important). so after above command, i used following linux command for recursive subfolders change:

for i in $(find /home/myaccountname/public_html -iname "*wp-content*" -o -iname "*wp-includes*" -type d -exec find {} -type d \;);do chmod 555 $i;done
it search whole /home/myaccountname/public_html path incl. subfolders for wp-content and wp-includes, find directories which has these phrasses in path and change permission so to disallow writing new changes/files into them.

All options: if you are using any plugins which caching dynamic page elements as files, this plugin may stop working, stop be able to create files. Example my plugin "widget-cache" shown error "Fatal error: Cache file not writeable! in /home/*/public_html/wp-content/plugins/wp-widget-cache/inc/wcache.class.php on line 286", i removed this error by making this plugin cache files writable (changing their permissions): find . -path "*/wp-content/widget-cache/*" -type f -exec chmod 644 {} \;

NOTE: After disabled writting into folders/files, you cant install any wordpress plugins without write permission to 3 folders: wp-content, wp-content/upgrade, wp-content/plugins
Enable write permission temporarilly for these folders:
# cd /home/yourusername/public_html
# chmod 755 wp-content wp-content/plugins wp-content/upgrade
then install/uninstall plugin and then disable writing again:
# chmod 555 wp-content wp-content/plugins wp-content/upgrade

IF REINFECTED: In case malicius files was still added into your site or files modiffied even you removed writing permission, it can mean that someone know hosting account password or there is some malicious script which changing file/folder permissions. Try to use linux tool "chattr (http://linux.die.net/man/1/chattr)" to enable immutable parameter for your folders/files.
Lock files:
# chattr +i /path/to/your/wordpress/folder -R
Unlock files:
# chattr -i /path/to/your/wordpress/folder -R
It means not even root can change permissions of files/folders or change its contents, if immutalbe (i) is in place.

# END OF TIP 4

# TIP 5

Find & block IP of person who abusing your hosting. If you discovered from Apache access log that IP address which accessed malicious script is always (on each re-infection) from same country like China, you may try to block this whole country IPs by adding them into .htaccess file located in your website root directory (same like index.php). I used this tool: https://www.countryipblocks.net/country_selection.php (or google: htaccess country IP deny) To veriffy that blocks really works, example google: "china web proxy" and access your website via that proxy (u need to ensure that this proxy site is really hosted in that forbidden country (put it into myip.ms)).

----
Another non tested thing. Password protect the directory (http://internetlifeforum.com/php-mysql-forum/3125-how-password-protect-some-directory-apache-server-using-htaccess-htpasswd/) like wp-includes

# TIP 6
disallow URL ending with .php to be opened/executed: http://internetlifeforum.com/php-mysql-forum/4096-disallow-opening-calling-executing-php-file-directly/


My oppinion/sumary:

1. i think most effective is to setup automated, regular backups of the website files and database so i can recover it (# TIP 0)
2. use file manager or linux shell to list wordpress folders/files and sort them by modification date, so you can find last modified/created files (can be malicious ones), so cleaning bad files
3. then disable writing into all wordpress folders (# TIP 4, Option A), possibly applying immutable parameter via linux command line as mentioned above (chattr +i /path/to/your/wordpress/folder -R)

Another Wordpress hardening tips:
http://www.esecurityplanet.com/open-source-security/top-5-wordpress-vulnerabilities-and-how-to-fix-them.html
https://codex.wordpress.org/Hardening_WordPress

emanuelsharper
09-03-2014, 01:21 PM
That is very useful post for technical users. For non-tech WP users, some simple ways I often do to secure my Wordpress blogs are:

1. never set username as "admin"
2. use strong login passwords
3. install anti-spam plugins: Akismet, Accurate Form Data, Disable Comments

kumkum
10-30-2021, 03:07 PM
Its very important to secure your Wordpress application and there are various ways to secure your application.
You have to make your application up to date, use strong password for admin and also use .htaccess file to secure your Wordpress.
Also you can use Wordfence plugin to secure your. You can also check step by steps process to secure your wordpress (https://hoststud.com/resources/using-wordfence-to-secure-your-wordpress-website-a-complete-guide.904/).

Gimli
11-06-2021, 02:30 PM
Nice post

You can use a plugin for your website like wordfence or bbq which will change htaccess file and add the majority of the htacces rules, dissolow executionalble files amongst a whole bunch of other things. Also add a web application firewall, however it does also hurt site performance so this is a nice little tutorial for manually hardening your website.

I love that the first thing you said was backup, I totally agree so many people talk about how to secure your website and never mention backing it up.
Must also mention there are items on your posts such as password-protecting folders that are not as far as I know implemented by any plugins and the ting is plugins also always bring their own risks.. so great post mate.