20 Steps To A Flexible and Secure WordPress Installation
20 Steps To A Flexible and Secure WordPress Installation
20 Steps To A Flexible and Secure WordPress Installation
random.org to generate a random prefix string which youll need to set as the $table_prefix
in wp-config.php. In addition, make sure to add an underscore at the end of the prefix.
Options -Indexes
Add/Remove www to prevent content duplication (replace example.com with your domain):
1. # Add www (change www.example.com to example.com to remove www)
2. RewriteCond %{HTTP_HOST} !^www.example.com$ [NC]
3. RewriteRule ^(.*)$ http://www.example.com/$1 [R=301,L]
WordPress requires you to redirect all non-files and directories to index.php:
1. RewriteCond %{REQUEST_FILENAME} !-f
2
17. </FilesMatch>
Secure the .htaccess file:
1. <Files .htaccess>
2.
Order Allow,Deny
3.
4. </Files>
Secure the wp-config.php file:
1. <Files wp-config.php>
2.
Order Deny,Allow
3.
4. </Files>
Secure .svn directories, as explained in step #2:
1. RewriteRule ^(.*/)?.svn/ - [F,L]
If you would like to add more configuration for your website and are looking for a general
tutorial, consider Nettuts Ultimate Guide to htaccess Files or Stupid htaccess Tricks on
Perishable Press.
PHP (gzip.php):
1. <?php
2.
3.
4.
5.
6. ?>
This may look a bit daunting at first, but it really isnt too bad. The large boolean expression
checks whether gzip is available and, if so, its applied. Unfortunately, I have found that this
gzip method doesnt function well with WordPress load-styles.php and load-scripts.php. As a
result, the preg_match is used to exclude them.
.htaccess:
1. <FilesMatch ".js$">
2. AddHandler application/x-httpd-php .js
3. php_value default_mimetype "text/javascript"
4. </FilesMatch>
5. <FilesMatch ".css$">
6. AddHandler application/x-httpd-php .css
7. php_value default_mimetype "text/css"
8. </FilesMatch>
9. <FilesMatch ".(htm|html|shtml)$">
10. AddHandler application/x-httpd-php .html
11. php_value default_mimetype "text/html"
12. </FilesMatch>
13. php_value auto_prepend_file /absolute/path/to/gzip.php
This snippet adds the php handler to .html, .css, and .js files so that they can be gzipped. It also
prepends the previously mentioned gzip.php file. Make sure to change
/absolute/path/to/gzip.php to the correct path.
3. # ESSENTIALS
4. RewriteEngine on
5. ServerSignature Off
6. Options All -Indexes
7. Options +FollowSymLinks
8.
9. # FILTER REQUEST METHODS
10. <IfModule mod_rewrite.c>
11. RewriteCond %{REQUEST_METHOD} ^(TRACE|DELETE|TRACK) [NC]
12. RewriteRule ^(.*)$ - [F,L]
13. </IfModule>
14.
15. # BLACKLIST CANDIDATES
16. <Limit GET POST PUT>
17. Order Allow,Deny
18. Allow from all
19. Deny from 75.126.85.215 "# blacklist candidate 2008-01-02 = admin-ajax.php attack
"
20. Deny from 128.111.48.138 "# blacklist candidate 2008-02-10 = cryptic character strin
gs "
21. Deny from 87.248.163.54 "# blacklist candidate 2008-03-09 = block administrative a
ttacks "
22. Deny from 84.122.143.99 "# blacklist candidate 2008-04-27 = block clam store loser
"
23. Deny from 210.210.119.145 "# blacklist candidate 2008-05-31 = block _vpi.xml attac
ks "
24. Deny from 66.74.199.125 "# blacklist candidate 2008-10-19 = block mindless spider
running "
25. Deny from 203.55.231.100 "# 1048 attacks in 60 minutes"
6
27. </Limit>
28.
29. # QUERY STRING EXPLOITS
30. <IfModule mod_rewrite.c>
31. RewriteCond %{QUERY_STRING} ../ [NC,OR]
32. RewriteCond %{QUERY_STRING} boot.ini [NC,OR]
33. RewriteCond %{QUERY_STRING} tag=
[NC,OR]
[NC,OR]
[NC,OR]
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
# SPECIFIC EXPLOITS
113.
114.
115.
116.
117.
118.
119.
120.
121.
122.
123.
124.
125.
126.
127.
128.
129.
</IfModule>
A few of these rules are commented out or edited because they interfere with WordPress. If
you are having problems with certain URLs, fix them by prepending a # (comment) to the
corresponding rule.
For further security, these plugins, referenced from DigWPs WordPress lockdown article, are
also important:
WP Security Scan
Secure WordPress
To make installation easy, you can run the following in command-line under your plugins
directory:
1. wget http://downloads.wordpress.org/plugin/all-in-one-seo-pack.zip
2. wget http://downloads.wordpress.org/plugin/google-sitemap-generator.3.2.4.zip
3. wget http://downloads.wordpress.org/plugin/wordpress-file-monitor.2.3.3.zip
11
4. wget http://downloads.wordpress.org/plugin/wp-security-scan.zip
5. wget http://downloads.wordpress.org/plugin/ultimate-security-check.1.2.zip
6. wget http://downloads.wordpress.org/plugin/secure-wordpress.zip
7. find . -name '*.zip' -exec unzip {} ;
8. rm *.zip
This will retrieve zip files for the plugins, unzip them, and delete the .zips
These download links may not be correct later on due to plugin updates. As a result, you can
visit the wordpress.org plugin pages listed above in order to find the updated links.
After you finish installing the plugins, make sure to enable them through the WordPress
dashboard.
Under Settings > Secure WP, check Error Messages and Windows Live Writer for extra
protection.
Note that there is a new Security tab created by WP Security Scan. Fix items in red under
Security > Security and Security > Scanner. When you visit Security > Scanner, make sure to
chmod all of your individual plugins with 755 as well. Furthermore, you can use the password
tool to generate a strong password.
Finally, fix the errors under Tools > Ultimate Security Check and ensure your site receives an
A.
Congratulations! You now have a flexible, secure, and comprehensive WordPress installation.
Use it wisely!
Great tutorial for locking down a fresh WordPress install. This is a must considering all of the
malware and link injections going around. The .htaccess and blacklist are perfect. Thank you!
There is a relatively easy way. Export your database into an SQL file, open it in a text editor,
do a find and replace, and then re-import.
Of course if youre doing a find an replace for wp_ that might be a little scary, so youll
have to make sure to do something like find: CREATE TABLE `wp_ and INSERT INTO
`wp_
You might also want to look into TAC for themes to make sure they are clean if you are
grabbing them from anywhere other than WP.org.
http://wordpress.org/extend/plugins/tac/
Some good suggestions here. I disagree with installing via SVN though. If, like me, you use
subversion to control theme and/or plugin updates that you develop, then it will clash with the
svn of the core, leaving possible conflict to deal with further down the line. Instead of
13
checking out from the core repository, you could use the export command that will leave out
the .svn folders everywhere.
SVN will only keep core WordPress files and the default plugins (Akismet and Hello Dolly)
under revision control. As a result, you can safely keep your themes/plugins under
SVN/Git/Mercurial/etc. without conflict.
Be very careful running the WP Security Scan plugin. This plugin can leave you without
admin access to your blog, as happened to me last night after running it. This blog provides the
SQL code you need to complete the work started by WP Security Scan and regain admin
access to your blog.
July 29, 2010 at 3:22 am
My current WordPress 3.0 install has the following .htaccess file that was automatically built
by wordpress:
# BEGIN WordPress
RewriteEngine On
RewriteBase /
RewriteRule ^index.php$ [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
# END WordPress
In steps 11 and 13 above, you give 2 different pieces of advice on setting up your .htaccess
file. Im a little confused as to which to use, for instance there are 2 different versions of this:
RewriteRule . index.php [PT] # from step 11 above
And
Nick
July 30, 2010 at 4:59 am
thanks for sharing this useful list!!
btw: the line 42 of the edited Perishable Press 4G Blacklist shouldnt be typed in like this:
RewriteCond %{QUERY_STRING} ^.*(request|select|insert|union|declare|drop).* [NC]
cause the select in this line generate a 403 error while using the automated multi-update
funktion for plugins, themes, etc in WP. if u change the line like this:
RewriteCond %{QUERY_STRING} ^.*(request|insert|union|declare|drop).* [NC]
it works like it should at least in my WP blogs.
14
Caused the drag and drop of widgets to not work anymore. Otherwise, great post.
January 13, 2011 at 1:16 am
Great article on securing wordpress. I love wordpress however the security vunerabilities have
always worried me, have had my website attacked by injection attacks several times. Also
most NB keep wordpress up to date!
15
Reply
Ive read a lot about some of these steps but its really nice to see them all in one place though.
One thing Id definitely consider is updating as more plugins come out.
One in particular comes to mind which is WordPress SEO by Yoast. You can check it out here:
http://yoast.com/wordpress/seo/
I used to use All in one SEO and Headspace 2 ( depending on the site ) for various projects,
but nowadays I use WordPress SEO for nearly all of my project. This is an incredible plugin
that I think should at least be given a look. Definitley for more advanced SEO tracking, but
there is a great guide on wpbeginner.com that shows how to optimize it well.
Reply
The 4G Blacklist breaks some features in admin. Some requests to files like get-scripts.php get
black listed and and in some cases jQuery doesnt load. You can see that in action in widgets
area.
June 1, 2011 at 1:29 pm
Very nice, in depth article. I cannot believe the wealth of information here. Thank you very
much for taking the time to put this together, it is a great reference as mentioned before. I have
also put together an article on WordPress security if interested it is here:
http://www.itutorblog.com/2011/06/how-to-secure-wordpress/
1.
Nick K
If youre using TimThumb on your WordPress website, comment the following line out in the
4G Blacklist:
RewriteCond %{QUERY_STRING} http: [NC,OR]
July 29, 2011 at 1:36 am
Great article, thanks!
For WordPress 3.2.1, comment out in your htaccess rules
RewriteCond %{QUERY_STRING} http: [NC,OR]
WP uses this in string to redirect after login.
If youre on https, comment out
RewriteCond %{QUERY_STRING} https: [NC,OR]
Same reason as above
Also, remove drop from this line
RewriteCond %{QUERY_STRING} ^.*(request|select|insert|union|declare|drop).* [NC]
or you wont be able to drop widgets in to sidebars in admin
If you are developing on localhost, comment in in htaccess
RewriteCond %{QUERY_STRING} ^.*(%0|%A|%B|%C|%D|%E|%F|127.0).* [NC,OR]
16
17