Sie sind auf Seite 1von 17

20 Steps to a Flexible and Secure WordPress Installation

Karthik Viswanathan on Jul 26th 2010 with


Tutorial Details:Topic: WordPress ;Difficulty: Easy;Completion Time: 20-30 minutes

Step 1: Get WordPress from SVN


The number one mistake for a flexible WordPress installation happens right from the get-go.
Ive seen numerous developers manually download, unzip, and upload WordPress to their site.
This is not only a waste of time, but it also reduces flexibility.
If you download WordPress from SVN, all you need to do is run the following in commandline:
1. svn co http://core.svn.wordpress.org/tags/3.0 .
Maybe you want the latest developer version. Thats even simpler:
1. svn co http://core.svn.wordpress.org/trunk/ .
Why is this so useful? For starters, all it takes is one command. Looking at WordPress in a
long-term perspective reveals that SVN also provides the simplest, hassle-free way to update
to a new stable version (or even downgrade). For example, lets say you want to update to
version 3.0. All you need to do is run the SVN switch command:
1. svn sw http://core.svn.wordpress.org/tags/3.0/ .
How easy was that? Note that if youre using the developer version, updating is even easier:
1. svn up
Thats all it takes. If you ever need the URL to a new stable version repository, visit the
WordPress Codex. You can also find full instructions on using SVN there.
Looking at WordPress in a long-term perspective reveals that SVN also provides the
simplest, hassle-free way to update to a new stable version (or even downgrade).

Step 2: Secure .svn Directories


Now that youre using SVN, you must ensure that your .svn directories are protected from the
public. One main reason lies in the .svn/entries file, which can give out sensitive information
to attackers. For further information regarding this subject, please take a look at Smashing
Magazines article on the SVN server admin issue.
To secure .svn directories using .htaccess, just apply the following redirect rule:
1. RewriteRule ^(.*/)?.svn/ - [F,L]

Step 3: Create wp-config.php


As outlined in the famous 5-minute WordPress installation, youll need to rename wp-configsample.php to wp-config.php and add in your database information.

Step 4: Add a Unique Database Prefix and Authentication Keys


Leaving your wp-config.php file only with database information and no other configuration is
a security issue. Make sure to generate authentication keys, as outlined in the comments. To
do so, visit https://api.wordpress.org/secret-key/1.1/salt/ and copy-paste the randomly-created
keys into the file.
Note that you should also change the default WordPress database table prefix. This is to secure
your installation against hacks, such as the recent outbreak of the Pharma Hack. Visit
1

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.

Step 5: Install Using wp-admin/install.php


As usual, visit wp-admin/install.php in your browser and follow the instructions. When filling
out the form, change the default administrator username (admin) in order to increase
security. Note that most attackers will target a WordPress installation with default settings.
Thus, changing this username is a must.
Note that most attackers will target a WordPress installation with default settings.

Step 6: Remove wp-admin/install.php


This is a commonly-omitted step which only takes a few seconds to execute. Simply remove
the wp-admin/install.php script after installing WordPress for further security.

Step 7: Login to the Dashboard and Complete User Profile


Login to your WordPress installation at http://example.com/wp-admin, click your username in
the top-right corner, and fill out your user profile.

Step 8: Edit Tagline and Timezone


Under the Settings > General tab, make sure to edit your blogs timeline as well as timezone.

Step 9: Review Writing, Reading, and Discussion Settings


Although you might not have to change anything, looking over Settings > Writing, Settings >
Reading, and Settings > Discussion is always a good idea. Ensure that the configuration meets
your standards.

Step 10: Change Permalink Structure


A default WordPress installation comes with query-string permalinks that look like
http://example.com/?p=1 for each article. Not only is this not search-engine friendly, but its
also not even human-friendly. Change this to a permalink structure that contains the title of the
post (%postname% if youre using a custom configuration).

Step 11: Add .htaccess Rules


An .htaccess file is necessary for your WordPress site to function correctly.
To begin, turn on the RewriteEngine:
RewriteEngine On
Disable directory listings for security purposes:

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

2. RewriteCond %{REQUEST_FILENAME} !-d


3. RewriteRule . index.php [PT]
Disable ETags:
1. Header unset ETag
2. FileETag None
Suppress PHP errors (note that this might not work on all hosts):
1. php_flag display_startup_errors off
2. php_flag display_errors off
3. php_flag html_errors off
4. php_value docref_root 0
5. php_value docref_ext 0
Control caching on files to speed up your site:
1. ExpiresActive On
2. ExpiresDefault A0
3. <FilesMatch ".(gif|jpg|jpeg|png|swf)$">
4. # 2 weeks
5. ExpiresDefault A1209600
6. Header append Cache-Control "public"
7. </FilesMatch>
8. <FilesMatch ".(xml|txt|html)$">
9. # 2 hours
10. ExpiresDefault A7200
11. Header append Cache-Control "proxy-revalidate"
12. </FilesMatch>
13. <FilesMatch ".(js|css)$">
14. # 3 days
15. ExpiresDefault A259200
16. Header append Cache-Control "proxy-revalidate"
3

17. </FilesMatch>
Secure the .htaccess file:
1. <Files .htaccess>
2.

Order Allow,Deny

3.

Deny from all

4. </Files>
Secure the wp-config.php file:
1. <Files wp-config.php>
2.

Order Deny,Allow

3.

Deny from all

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.

Step 12: Use gzip


Applying gzip can compress text files up to 80% and greatly save bandwidth. Making it active
on your site only requires a PHP file and a bit of .htaccess. Note that the following code is
referenced from a gzip tutorial on Lateral Code.

PHP (gzip.php):
1. <?php
2.

3.
4.
5.

if( isset( $_SERVER['HTTP_ACCEPT_ENCODING'] ) && substr_count( $_SERV


ER['HTTP_ACCEPT_ENCODING'], 'gzip' ) && !preg_match( '/(load-styles|loadscripts).php/', $_SERVER[ 'SCRIPT_NAME' ] ) )
ob_start( 'ob_gzhandler' );
else
ob_start();
4

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.

Step 13: Apply the 4G Blacklist


Perishable Press 4G Blacklist will prevent numerous attacks on your website through
.htaccess. Ive included the code below (edited for WordPress). You can learn about how it
works by reading the article on Perishable Press:
1. ### PERISHABLE PRESS 4G BLACKLIST ###
2.
5

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

26. Deny from 24.19.202.10

"# 1629 attacks in 90 minutes"

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]

34. RewriteCond %{QUERY_STRING} ftp:

[NC,OR]

35. RewriteCond %{QUERY_STRING} http:

[NC,OR]

36. RewriteCond %{QUERY_STRING} https: [NC,OR]


37. RewriteCond %{QUERY_STRING} mosConfig [NC,OR]
38. # RewriteCond %{QUERY_STRING} ^.*([|]|(|)|<|>|'|"|;|?|*).* [NC,OR]
39. # RewriteCond %{QUERY_STRING} ^.*(%22|%27|%3C|%3E|%5C|%7B|%7C).* [N
C,OR]
40. RewriteCond %{QUERY_STRING} ^.*(%0|%A|%B|%C|%D|%E|%F|127.0).* [NC,O
R]
41. RewriteCond %{QUERY_STRING} ^.*(globals|encode|localhost|loopback).* [NC,O
R]
42. RewriteCond %{QUERY_STRING} ^.*(request|select|insert|union|declare|drop).* [N
C]
43. RewriteRule ^(.*)$ - [F,L]
44. </IfModule>
45.
46. # CHARACTER STRINGS
47. <IfModule mod_alias.c>
48. # BASIC CHARACTERS
49. RedirectMatch 403 ,
7

50. RedirectMatch 403 :


51. RedirectMatch 403 ;
52. # RedirectMatch 403 =
53. RedirectMatch 403 @
54. RedirectMatch 403 [
55. RedirectMatch 403 ]
56. RedirectMatch 403 ^
57. RedirectMatch 403 `
58. RedirectMatch 403 {
59. RedirectMatch 403 }
60. RedirectMatch 403 ~
61. RedirectMatch 403 "
62. RedirectMatch 403 $
63. RedirectMatch 403 <
64. RedirectMatch 403 >
65. RedirectMatch 403 |
66. RedirectMatch 403 ..
67. # RedirectMatch 403 //
68. RedirectMatch 403 %0
69. RedirectMatch 403 %A
70. RedirectMatch 403 %B
71. RedirectMatch 403 %C
72. RedirectMatch 403 %D
73. RedirectMatch 403 %E
74. RedirectMatch 403 %F
75. RedirectMatch 403 %22
8

76. RedirectMatch 403 %27


77. RedirectMatch 403 %28
78. RedirectMatch 403 %29
79. RedirectMatch 403 %3C
80. RedirectMatch 403 %3E
81. # RedirectMatch 403 %3F
82. RedirectMatch 403 %5B
83. RedirectMatch 403 %5C
84. RedirectMatch 403 %5D
85. RedirectMatch 403 %7B
86. RedirectMatch 403 %7C
87. RedirectMatch 403 %7D
88. # COMMON PATTERNS
89. Redirectmatch 403 _vpi
90. RedirectMatch 403 .inc
91. Redirectmatch 403 xAou6
92. Redirectmatch 403 db_name
93. Redirectmatch 403 select(
94. Redirectmatch 403 convert(
95. Redirectmatch 403 /query/
96. RedirectMatch 403 ImpEvData
97. Redirectmatch 403 .XMLHTTP
98. Redirectmatch 403 proxydeny
99. RedirectMatch 403 function.
100.

Redirectmatch 403 remoteFile

101.

Redirectmatch 403 servername


9

102.

Redirectmatch 403 &rptmode=

103.

Redirectmatch 403 sys_cpanel

104.

RedirectMatch 403 db_connect

105.

RedirectMatch 403 doeditconfig

106.

RedirectMatch 403 check_proxy

107.

Redirectmatch 403 system_user

108.

Redirectmatch 403 /(null)/

109.

Redirectmatch 403 clientrequest

110.

Redirectmatch 403 option_value

111.

RedirectMatch 403 ref.outcontrol

112.

# SPECIFIC EXPLOITS

113.

RedirectMatch 403 errors.

114.

# RedirectMatch 403 config.

115.

RedirectMatch 403 include.

116.

RedirectMatch 403 display.

117.

RedirectMatch 403 register.

118.

Redirectmatch 403 password.

119.

RedirectMatch 403 maincore.

120.

RedirectMatch 403 authorize.

121.

Redirectmatch 403 macromates.

122.

RedirectMatch 403 head_auth.

123.

RedirectMatch 403 submit_links.

124.

RedirectMatch 403 change_action.

125.

Redirectmatch 403 com_facileforms/

126.

RedirectMatch 403 admin_db_utilities.

127.

RedirectMatch 403 admin.webring.docs.


10

128.

Redirectmatch 403 Table/Latest/index.

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.

Step 14: Activate Akismet


Activating Akismet is a must in order to prevent comment spam.
Activating Akismet is a must in order to prevent comment spam. Do so by registering for an
API key at akismet.com. Note that a WordPress.com account API key will also work.
Once you obtain a key, visit Plugins > Akismet Configuration in your dashboard and paste it in
the corresponding box.

Step 15: Download Plugins


The following plugins are a great help to any WordPress blog:

All in One SEO Pack

Google XML Sitemaps

For further security, these plugins, referenced from DigWPs WordPress lockdown article, are
also important:

WordPress File Monitor

WP Security Scan

Ultimate Security Check

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.

Step 16: Configure All in One SEO Pack


Before All in One SEO Pack becomes active, youll need to configure it. Go to Settings > All
in One SEO to do so. Make sure to mark the enabled radio button. In addition, add in a
home title, description, and keywords. Finally, set the rest of the options to your liking.

Step 17: Generate a Sitemap


Visit Settings > XML-Sitemap to generate your first sitemap that will be sent to search
engines. Before doing so, ensure that the options on the page are what you desire. For
example, I often edit the change frequencies, as my posts are modified quite often.
Once you are ready, scroll to the top of the page and click the build link (Click here). You
might have to create two blank filessitemap.xml and sitemap.xml.gzin your root directory
depending on the directory permissions. Nevertheless, once you finish building it for the first
time, it should automatically update as long as you have Rebuild sitemap if you change the
content of your blog checked.

Step 18: Add Security


At this point, youve already installed four security plugins. You should now put them into use.
Visit Settings > WordPress File Monitor and add wp-content/uploads in the exclude path.
Change the other information if necessary. Note that this plugin will inform you whenever it
notices a change in your file system.
12

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.

Step 19: Customize Theme and Sidebar


Now that youve setup a flexible, secure WordPress installation, youll need to make it
comprehensive by customizing the theme and sidebar to fit your sites needs. Of course, there
is no set method to accomplish this; each site is unique in its own way. Make a theme that
appeals to both you and your readers.

Step 20: Write Content


All thats left now is to write genuine content that appeals to your user base. You now have a
flexible, secure, and comprehensive WordPress installation. Use it wisely.

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

RewriteRule . /index.php [L] # created by wordpress 3.0

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

have a nice day.


Marvin
I feel this was pretty hard to understand for me. i had never worked with htaccess before and i
didnt know what i was doing so i had to ask on some other community why and what..
Iam normally a login hosting-admin guy that clicks on the one-click installer button and
WordPress is ready to go. * but that doesnt work fine.
Your Command-Line:
I dont know if it was me doing it wrong but at #15 after the command-line in the Terminal i
had all my zip file on my computer unzipped. :S
Now i can clean up again! :S
000Now i have trouble with my sitemap files..
I think it has everything to do with all the htaccess changes i made.
I did everything like in step#17.
First i created one empty tekst-editor file and named it sitemap.txt after that i changed it to
sitemap.xml and duplicated it and named it sitemap.xml.gz
After that i uploaded them to my hosting in the same directory where the index.html /
index.php file goes.
But nothing i get this error!
There was a problem writing your sitemap file. Make sure the file exists and is writable.
** Same line for the Gzip verson ***
I when looking in my hosting admin, to see what the permissions are on the file.
and it says the following:
Owner: read mode, write mode
Group: read mode
Others: read mode
Somebody knows where it goes wrong?
August 10, 2010 at 10:03 pm
The GZip method is causing me not to be able to install or upgrade plugins directly through
WordPress. Is anyone else having this problem?
The line below

RewriteRule ^(.*)$ [F,L]

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

and remove localhost from


RewriteCond %{QUERY_STRING} ^.*(globals|encode|localhost|loopback).* [NC,OR]
August 30, 2011 at 12:52 pm
You do not need to parse request header to make use of
ob_start( ob_gzhandler );
Just place that single command in, in case compression is not supported by the browser, it
wont be activated. No need for the ifs around and such. See the php documentation about
that command for more info.
Excellent points, Let me add some more points:
Alot of people use the default Admin and weak passwords like test or 12345.
My suggestion is to use very strong password comprising of Alphanumeric with special letters.
Another tip is, do not delete the default admin, rather create a new user with full privileges and
restrict the admin to just a subscriber, so even if some one guess your password or some how
got access to the Admin account, he/she will have limited access.
Thanks.

17

Das könnte Ihnen auch gefallen