Three tips to protect your WordPress installation

January 17, 2008

in How to, Linux/Ubuntu, Weblog/blog

Here are three easy but important ways to protect yourself if you run a WordPress blog:

  1. Secure your /wp-admin/ directory. What I’ve done is lock down /wp-admin/ so that only certain IP addresses can access that directory. I use an .htaccess file, which you can place directly at /wp-admin/.htaccess . This is what mine looks like:

    AuthUserFile /dev/null
    AuthGroupFile /dev/null
    AuthName “Access Control”
    AuthType Basic
    order deny,allow
    deny from all
    # whitelist home IP address
    allow from 64.233.169.99
    # whitelist work IP address
    allow from 69.147.114.210
    allow from 199.239.136.200
    # IP while in Kentucky; delete when back
    allow from 128.163.2.27

    I’ve changed the IP addresses, but otherwise that’s what I use. This file says that the IP address 64.233.169.99 (and the other IP addresses that I’ve whitelisted) are allowed to access /wp-admin/, but all other IP addresses are denied access. Has this saved me from being hacked before? Yes.

  2. Make an empty wp-content/plugins/index.html file. Otherwise you leak information on which plug-ins you run. If someone wanted to hack your blog, they might be able to do it by discovering that you run an out-of-date plugin on your blog and then they could exploit that.
  3. Subscribe to the WordPress Development blog at http://wordpress.org/development/feed/ . When WordPress patches a security hole or releases a new version, they announce it on that blog. If you see a security patch released, you need to upgrade or apply the patch. You leave yourself open to being hacked if you don’t upgrade.

And here’s a bonus tip: in the header.php file for your theme, you might want to check for a line like

<meta name=”generator” content=”WordPress <?php bloginfo(’version’); ?>” /> <!-– leave this for stats please -->

I’d just go ahead and delete that line or at least the bloginfo(’version’). If you’re running an older version of WordPress, anyone can view source to see what attacks might work against your blog.

Hat tip to Reuben Yau and Shoe.

Update: In the comments, Joshua Slive pointed out that the .htaccess file shouldn’t have a <LIMIT GET> around the IP addresses. That would have allowed IP addresses to POST, for example. Joshua, thanks for the pointer to the Apache docs on this point.

{ 125 comments… read them below or add one }

Brajeshwar January 17, 2008 at 10:45 pm

1. Why would this IP restriction be more effective than a password protection using the similar .htaccess and .htpasswd method which offers the same level of protection sans the changing of IPs when you move/travel. And let your browser/keychain remember you password so you can just hit enter when prompted.

2. I’m pretty sure most web host have directory browsing turn-off by default and in that case, won’t it show a 404 page thus going to that location makes no sense. However for those not doing that, I’m pretty sure they have a reason and if they’re to follow your steps, they must have been smart enough to do a directory browsing off through their Web Host Panel or through .htaccess.

3. This is the least updated feed and we’re talking about Wordpress, you’ll definitely hear about new releases within days unless you’re on an extended vacation.

Bob January 17, 2008 at 10:56 pm

And don’t let Google know you are doing paid blog postings on your Wordpress blog….

Multi-Worded Adam January 17, 2008 at 11:00 pm

LMAO!

Dude, I love the reverse DNS on those IPs. That’s some classic geek humor right there.

http://whois.domaintools.com/64.233.169.99

http://whois.domaintools.com/69.147.114.210
http://whois.domaintools.com/199.239.136.200

Gotta love the conflict of interest between “home” and “work”. But the NYT moonlighting…you gonna start writing freelance op-ed SEO articles? :D

Gary Jones :: BlueFur.com January 17, 2008 at 11:06 pm

If your the root user on the server set the ownership of the file to root so only the root user can modify it.

travis lane January 17, 2008 at 11:12 pm

Just out of curiousity–if the IP address trick prevented the hack–how did you know it would’ve been successful otherwise?

Lots of people do random scans on the wp-admin directory.

Johannes January 17, 2008 at 11:20 pm

Security through obscurity, great tip :-)

Vlad - Small Business and Web Design January 17, 2008 at 11:37 pm

I tried to password protect /wp-admin/, but my WordPress took it seriously and instead of asking for login/password combo it dumps me straight to the index page. Never seen this before.

marty January 17, 2008 at 11:52 pm

Rather than creating a blank index.html in the plugins directory to prevent directory browsing, you can disable it by adding the following to your .htaccess file, and the webserver will return a 403:

# prevent directory browsing
Options -Indexes

Alvaro January 18, 2008 at 12:14 am

Hi Matt,

you could replace the 2nd point with another configuration of the .htaccess file:

Options FollowSymLinks
AllowOverride None

(You should put the right path to the plugins directory)

or

Options -Indexes

Boring Market January 18, 2008 at 12:51 am

Great tips!

Iliyan Darganov January 18, 2008 at 1:28 am

Hi, Matt
thanks for the great tips.

Another way to protect your wp-content folder is again with .htaccess:

Order Allow,Deny
Deny from all

Allow from all

Dean Clatworthy January 18, 2008 at 1:29 am

Nice bit of irony with your work IP address there Matt :P

Iliyan Darganov January 18, 2008 at 1:33 am

Ops, the htaccess content did not visualise correct. Here is a screenshot: http://img339.imageshack.us/img339/7439/htaccess1dp4.gif

Also have in mind that the version of Wordpress is not shown only in the meta tag. You can find it in the rss feed for example and in several other places.

Youssef CHAOUI January 18, 2008 at 1:42 am

Great post, for those who run under linx and have cpanel, you can just lock the wp-admin via the interface “Password Protect Directories” it’s more simple.

leafduo January 18, 2008 at 2:29 am

I think “Deny from all” is better.

(2nd point)

Jeff January 18, 2008 at 3:13 am

Now that you’ve told the world your IP addresses, won’t hackers be able to spoof theirs to yours to gain access?

Tim Wintle January 18, 2008 at 3:35 am

lol, thanks Dean Clatworthy, I wouldn’t have even looked at it otherwise :-)

@Matt Cutts – I think that this post will probably help webmasters in general more than any of the specific tips you give to site owners.

I’d have assumed that wordpress would have come with .htaccess files to secure the plugins directory. Perhaps you should suggest it to the wordpress developers?

btw, WEBSPAM-UK2007 is out. Sure you’ll be having lots of fun with it :-) – I was thinking of playing with it myself at home to test the [tiny] hadoop cluster I’ve just set up, but I’ve got another plan for that so it may have to wait … (I don’t have anything like the “infinate” number of processors Google seems to have, so running both jobs is out of the question)

@travis lane – if anyone tries to see my admin pages I class it as trying to hack in – perhaps with no damage, but it’s still something I would like to stop.

Oh, and some of you may be interested in a study I did recently on the growth of online video – see my blog for a link to it.

joshnunn January 18, 2008 at 3:39 am

What might someone use if they don’t have a reliably stable IP address?

Tim Wintle January 18, 2008 at 3:57 am

@ joshnunn – I don’t have that much experience with wordpress, but I would try one of the following if you really want lock-down:

- ssh tunnel in through a reliable ip address if you know how to do that

- rename your wordpress admin directory (not sure if this causes any problems with wordpress)

- set the wordpress admin directory to require a secure password and username

but not many of us will have as many people trying to hack our sites as I guess Matt does

Case Stevens January 18, 2008 at 4:27 am

Hi Matt.
Great tips.
I also took the vulnerable MYSQL settings out of the wp-config file, uploaded them in a separate file which I include in the wp-config.
Would that be an extra safety lock in your opinion?
Regards and thanks for the tips.
Case

Free WordPress Templates January 18, 2008 at 4:37 am

Instead of limiting the /wp-admin/ directory to only IPs via your .htaccess file, I just password protected the /wp-admin/ at the directory level. Then you can access it from anywhere in the world on a per user-level.

~David

PhotoTiki Chris January 18, 2008 at 5:08 am

As mentioned above, I think Options -Indexes is a better option for point 2 and can be added to point 1.

This way if you have an open directories in your installation they will be protected.

Lee January 18, 2008 at 6:25 am

Wow what a coincidence I wrote about these on Jan 9.
http://www.epiblogger.net/5-wordpress-security-essentials/

Amazing how things go around.

If you don’t have a static IP address you can use a range in the htaccess file for your ISP than at least it is narrowed down to just IP’s from your ISP. Check out Login Lockdown as well. It bans people by IP address if they enter the wrong user name and password after so many attempts.

Brian January 18, 2008 at 6:33 am

joshnunn’s and Tim Wintle’s comments have got me pondering now. Can anyone come up with a script that can ping a FQDN, translate it to an IP, and replace an old IP in an .htaccess file with the new one? This might be an elegant solution to my dynamic IP issue.

Another thought occurs – this would make for a great WordPress plugin! [aligns black candles in a pentagram] Joost De Valk, I invoke you…

Joshua Slive January 18, 2008 at 6:49 am

Your Apache httpd configuration is not secure. You need to delete the and lines. With these lines in place, you are explicitly ALLOWING access with any other method (POST, PUT, DELETE, etc). And many applications will be happy to serve requests using arbitrary methods (BLAH, for example). If you delete those two lines, all methods will be restricted, which is what you want.

The fact that this incorrect and dangerous configuration has persisted so long on the web (it hasn’t been correct since the NCSA days over 10 years ago) is an interesting phenomenon in itself. You obviously copy-pasted it from somebody else, who copy-pasted it from sombody else, etc. Nobody bothered to check the Apache httpd docs.

Also, less importantly, all the Auth* directives should be deleted since you aren’t using user authentication.

Joshua Slive January 18, 2008 at 6:51 am

Hmmm… your blog ate the most important part of my comment because it was between angle brackets. Seems kind of lame.

You need to delete the
Limit GET
and
/Limit
lines (with angle brackets).

Omar Yesid Mariño January 18, 2008 at 6:54 am

Thank you very much, Matt. This is really useful for me. Security on Internet is never enough.

Brian McDowell January 18, 2008 at 7:00 am

Thank you for this write up Matt. I am sure this quick post will help many people (myself included). I run multiple blogs and am in the process of implementing this.

Much respect.

Ben Rabicoff January 18, 2008 at 7:18 am

Great tips Matt. I’m more than sure this could save people from a great deal of headaches! :)

Maurice January 18, 2008 at 7:26 am

I hope the ip adresses are fakes did you realy mean to give out your home ip address :-)

Brian January 18, 2008 at 7:37 am

Try browsing his “home address” on port 80. :D

Maurice January 18, 2008 at 7:57 am

:-) Just checking Matt

I have seen some boo boos where people have left things in they should’t have the cc/dd ap that had “passwd” as the password for example they had for got to change the example code that the gate way provider provided.

Matt Cutts January 18, 2008 at 8:19 am

travis lane, thanks to a kind person, I saw an attack against my blog before it got widely noticed.

Brian, I like the “require username and password” as the simplest option compared to writing that script.

Matt Cutts January 18, 2008 at 8:20 am

Dean Clatworthy, I picked the IP addresses as a little inside joke for the detail-oriented. :)

Matt Cutts January 18, 2008 at 8:21 am

Tim Wintle, thanks for the tip. I’ll have to check how we did. :)

Colin Smillie January 18, 2008 at 8:26 am

I’m suprised Akismet wasn’t mention with regards to spam prevention or even Defensio. I think most WP installations are plagued by comment spam now…

Garry Conn January 18, 2008 at 8:30 am

Matt,

That’s great stuff man… more awareness about WordPress security is definitely needed. There are so many people out there who are discovering blogging for the first time. They don’t know anything about programming, php, MySQL, etc… they are just merely creative people and writers who want to broadcast their writing on the Internet.

This is an awesome tip, because I think it is something that many installers can automatically include for their clients when they design, install, configure WordPress. I know that I’ll use it. Thanks for the great article.

Best Regards,
Garry Conn

Michael Clark January 18, 2008 at 9:03 am

Matt, your bonus tip isn’t enough. WordPress publishes your WP version number in lots of public places, such as in your feed. Use the noversion plugin found at http://blogsecurity.net/wordpress/bs-wp-noversion/ to hide your WP version number.

Tim Linden January 18, 2008 at 9:11 am

Is there a reason it’s only limiting GET and not POST also?

Nick-R January 18, 2008 at 9:40 am

Cheers for the post Matt,
i use wordpress a lot, its a great way of installing RSS into a site and a simple content management system for people who are non-computer literate .

Please keep us posted with any other faults that may be present.
Cheers
Nick R

Nick - I think the original Nick here. January 18, 2008 at 9:59 am

Great tips mat. You can also put -Indexes in the .htaccess file to block all open folders on the site.

Mich January 18, 2008 at 12:14 pm

More gold Matt, I swear from now on I’m reading your feed first thing every day. I would have never thought to use an ht lockout just for admin section. This was an awsome idea and I am going to setup some clients like this if I can think of a way to script an auto update to match dynamic ip changes.

I always just drop an index.htm in if I wanted to keep people out. But that is just to keep out the casual hacker, i ummmm.. errrr… ah hem, am pretty sure most of us know a determined foe will get in if they really want to.

This one great, wow(yes again with the WOW) it will effectively lock out almost anyone even those who really know their stuff will choke on that.

As always my friend Peace and thanks

Mich D.

Kshitij January 18, 2008 at 12:51 pm

That aint gonna work with dyna IPs. Perhaps if one could rename the directory or move it somewhere else :) .

Ben January 18, 2008 at 2:26 pm

I would also put out there keeping your installation of Wordpress up to date very good for security.

Dan January 18, 2008 at 2:32 pm

When I created the .htaccess file, I was blocked from my admin directory. I double-checked, and I know that I entered the correct IP address, and I know that my ISP doesn’t change my IP address. When I go to login, the login page appears unstyled (meaning the css for the page has been blocked) and then it sends me to the “Page not found” message on my blog. Any idea what might be causing the problem?

Robert January 18, 2008 at 3:02 pm

> allow from 64.233.169.99

So WordPress is the REAL technology behind Google? Unbelievable! Waiting for the other Matt to confirm this…

louis w January 18, 2008 at 3:19 pm

why don’t you just put a password on the admin dir using htaccess. if your password is strong enough its just as good as ip restriction. i doubt a spammer is going to try to crack a pw.

g1smd January 18, 2008 at 5:21 pm

When you protect a folder from access using the methods above, the URL returns a 403 error.

That still shows that viewer that the folder does actually exist, if they want to go dig a bit deeper.

If you internally rewrite the bare folder-only URL (both with and without a trailing slash) to an internal pathname that really does not exist, then you will serve a 404 error – just like all the other URLs on the site that do not exist.

RewriteRule ^protected/?$ /thisdoesnotexist [NC]

Fun with .htaccess and rewrites.

Erek Dyskant January 18, 2008 at 5:31 pm

Really neat ideas. Not just for wordpress, but everyone should limit the administrative functions of their web applications to known trusted IP addresses. It’s really amazing how much damage can be done with a little social engineering or packet sniffing for passwords.

Just one comment on your implmentation. the lime still allows POST requests, so I was still able to access your wp-admin page by creating a small html file:

and clicking the submit button.

You shouldn’t even need a directive. If you really want one: it should be:

order deny,allow
deny from all
# whitelist home IP address
allow from 64.233.169.99
# whitelist work IP address
allow from 69.147.114.210
allow from 199.239.136.200
# IP while in Kentucky; delete when back
allow from 128.163.2.27

deny from all

Erek Dyskant January 18, 2008 at 5:38 pm

My previous comment got garbled by the cross site scripting protection.
Here it is reproduced, except with parentheses instead of greater than and less than signs:

Really neat ideas. Not just for wordpress, but everyone should limit the administrative functions of their web applications to known trusted IP addresses. It’s really amazing how much damage can be done with a little social engineering or packet sniffing for passwords.

Just one comment on your implmentation: The (Limit GET) directive still allows POST requests, so I was still able to access your wp-admin page by creating a small html file and clicking the submit button, so my browser requests the page as a POST instead of a GET:

(form method=POST ACTION=http://www.mattcutts.com/blog/wp-admin/)
(input type=submit)
(/form)

Your system should work fine without the (Limit) and (/Limit) lines, but if you really want them it should look like:

(Limit GET POST PUT)
order deny,allow
deny from all
# whitelist home IP address
allow from 64.233.169.99
# whitelist work IP address
allow from 69.147.114.210
allow from 199.239.136.200
# IP while in Kentucky; delete when back
allow from 128.163.2.27
(/limit)

(LimitExcept GET POST PUT)
deny from all
(/LimitExcept)

spamhound January 18, 2008 at 5:57 pm

I go one step further and password protect the wp-admin directory in the control panel.

You can also turn indexing off for that plugin folder as added security.

Dave January 18, 2008 at 6:30 pm

LOL at those IP’s!!!

Afriend January 18, 2008 at 7:02 pm

To determine which content to display you have trusted ip’s,non trusted,and identified abuse ips then you vary the dispay of content as follows…….

1.Trusted ip (all content)
2.Non trusted ip (frame content or ajax content)
3.Ip abuse Ajax content only

Please delete

Afriend January 18, 2008 at 8:25 pm

Knowing enemy: Heres the list of 3 advertisers that support of spam sites the most.

1. Googleadsense and Doubleclick.
2. Yahoo
3. Ask

ganes | gadget January 18, 2008 at 8:32 pm

matt, about point 2. If i know the name of exploitable plugins, I can still access the plugins file. This if you only add index.html file to protect it.

I think it’s better to add

Options All -Indexes

into htaccess file in the root directory.

what say you, matt?

Ajit Gaddam January 19, 2008 at 8:25 am

Excellent Tips Matt. I added some more WordPress Security Tips to go along with those you listed out here

Kaloyan K. Tsvetkov January 19, 2008 at 11:08 am

I’d just go ahead and delete that line or at least the bloginfo(’version’). If you’re running an older version of WordPress, anyone can view source to see what attacks might work against your blog.

This is useless. Even if you hide the Wordpress version from the header file of your theme, it will still show itself on the login page (wp-login.php). Here is an example with this blog, which I got from here:

…link rel=’stylesheet’ href=’http://www.mattcutts.com/blog/wp-admin/wp-admin.css?version=2.3.2‘ type=’text/css’ …

See, the WP version pops up in the CSS declaration (in bold).

Kaloyan K. Tsvetkov January 19, 2008 at 11:19 am

Make an empty wp-content/plugins/index.html file. That’s fine and easy, but using .htaccess for the plugins is what I do and it works better then the index.html file before even with the index.html file the “hackers” can probe you to see if you have the plugin that they want to exploit. This is because hardly anyone changes the name of the plugin files or the folders the plugins file are stored in (plus there are a lot of sloppy WP plugins that will not work unless they have the “original” filename and location). Here’s an example: imagine there is an exploit in the akismet plugin, so you need to see if it is installed. There are several things you can do:

* try to load the URL for the folder where “akismet” should be – in the case of this blog it is accessible:

http://www.mattcutts.com/blog/wp-content/plugins/akismet/

You can see that it is accessible, and you can see the date it is uploaded, so you can figure out what could be the latest version of it (knowing the date of the latest release for the plugin in question).

* the above is not the case with all the blogs – some of them got the “index” option of the webserver disabled so they got 403 Forbidden error when they try to load the index for the “akismet” folder. In that scenario just try to load the plugin file itself – like this:

http://www.mattcutts.com/blog/wp-content/plugins/akismet/akismet.php

If the file is there you will see something like:

Fatal error: Call to undefined function add_action() in /usr/www/users/cutts/blog/wp-content/plugins/akismet/akismet.php on line 25

Those two “probing” scenarios are the reason I prefer to use .htaccess for my plugins folder, cutting off all web access to it.

Kaloyan K. Tsvetkov January 19, 2008 at 11:22 am

Make an empty wp-content/plugins/index.html file.

Another thing about this matter – you should fo this index.html thing to the /themes/ folder as well. Nowadays the themes are full of extra functionality, and soon there will be exploits for them as well, and an extra index.html prevention there will be OK.

Bruce Keener January 19, 2008 at 11:33 am

Excellent tips!
Took me a while to remember though that the quote marks do not copy properly when copying code directly from your post … it is necessary to edit to ensure real quote marks are used.

I’ve noted it before, but I am delighted you are in one of your “tech moods.” I enjoy all of your posts, but especially enjoy you breaking out of the mold from time to time.

Amit January 19, 2008 at 11:40 am

Hi Matt, some nice tips there.

Just want to let you know that on your blog why do u display the meta details that is links to the wordpress admin ? that is also a security hole.

Also locking the wp-admin file with a password protected .htaacess file will be best option. Please correct me If i am wrong.

shawn January 19, 2008 at 11:52 am

You know Matt, I never thought of or even knew that information. Please put me on your e-mail subscription list and keep me updated. I’d really appreciate that, because:

http://www.Drewryonline.net

are all WordPress blogs….:-)

Thanks again,

Shawn

Kenji January 19, 2008 at 12:41 pm

Does anyone else loose the dashboard contents after uploading their .htaccess in wp-admin ?

Dave (The Other One) January 19, 2008 at 2:02 pm

Overkill alert !!!

FYI…

#1 – There’s a little thing called “Apache Web Server” and it comes default with directory indexing turned off. 90% of all hosting companies have it turned off even on Windoze servers.

#2 – If you’re using Permalink’s with Wordpress, the .htaccess in your root directory should already cover this.

ahem *cough* *cough*, excuse me Mr. Cutts, but do I see you passing Pagerank to the two links at the end of your article. Did you forget your nofollow tag??? I know things have to be hurting over at the GooglePlex with GOOG stock down by almost 20% but really Matt, I never thought you’d be caught selling text links or writing sponsored blog posts :-)

Bruce Keener January 19, 2008 at 3:38 pm

Has anyone had trouble getting the Google Sitemaps Generator plugin to update a sitemap after restricting /wp-admin to your own IP address? I did the htaccess mod (thanks again, Matt) and just tried running the sitemap plugin a few minutes ago. It runs but does not seem to be updating the sitemap.

I could work around it by temporarily deleting my htaccess file in the wp-admin directory, but I wonder instead if it is just time to part with using a sitemap. Thoughts? I know it is a bit off topic, but the security updates resulted in me rethinking it. All of my pages have been indexed for sometime, so I do not know that the sitemap really adds any value.

Joshua Slive January 19, 2008 at 4:08 pm

I’m very surprised you haven’t corrected this entry yet, and disturbed by the number of people who are copy-pasting your broken example. This configuration has one of the most dangerous kinds of security problems: one which does not show up in a basic test, but is easily exploitable by someone who knows what is going on. Your site may or may not be exploitable at the moment; it depends on the details of your wordpress configuration. But in any case, why would you recommend an incorrect and possibly exploitable configuration when the correct and secure configuration is simpler than the incorrect one.

If you don’t believe me that your use of Limit is wrong, just read the bold print in the apache httpd docs:
http://httpd.apache.org/docs/2.2/mod/core.html#limit

SEO Tracker January 19, 2008 at 4:52 pm

WOW! I would not have thought of this! Thanks Matt!

Tony January 19, 2008 at 5:44 pm

Matt how do you modify the htaccess if you a dynamic ip address?

IncrediBILL January 20, 2008 at 2:29 am

I had WordPress on one of my servers and I found the easiest way to protect nyself was to get rid of WordPress.

Robert Accettura January 20, 2008 at 10:14 am

Because I’m a nice guy, I’ll throw you a few more good mods:

Use Admin SSL to force SSL for your blog’s login, otherwise your password is plain text and anyone can sniff it out.

Add to your .htaccess file:

IndexIgnore *

To never show indexes. That way someone can’t browse subdirectories in wp-content/plugins.

Kenji January 20, 2008 at 1:09 pm

A follow-up on my problem with the dashboard.

It does show-up if I access it through the …wp-admin/ but does not if I click on the dashboard button (url ends in wp-admin/admin.php?page=index.php).
This might not be a side-effect of the .htaccess after all.

I have also checked the Sitemap plugin and it failed to write the sitemap file.

David Saunders January 20, 2008 at 2:07 pm

I’d be happy if I could find a nice WP host that could set up a template I have ready and exclude the date part plus add the title, description tag in and add Google Analytics, Verification……

Plus all the nifty plug ins with no hassle….. Feel free to mail me if you know a really good, reasonable host that can get it right – please don’t say the Y! word…….

HELP!!!!

Tom Forrest January 20, 2008 at 4:33 pm

I own several WordPress based sites.

Does anyone know of a good consultant I could hire to do this for me? Matt, thank you for this very useful post, and excellent examples of exactly what needs to be done.

Tom

Matt Cutts January 20, 2008 at 10:53 pm

Joshua Slive, I’ve updated the post — thanks for pointing that out.

Multi-Worded Adam January 21, 2008 at 8:01 am

Hmmm… your blog ate the most important part of my comment because it was between angle brackets. Seems kind of lame.

You need to delete the
Limit GET
and
/Limit
lines (with angle brackets).

This is a WordPress thing, Joshua. It’s done (at least such is my understanding) to prevent people from arbitrarily putting in things like iframes and Javascripts that lead to other sites. The way around it is to explicitly type the &lt; and &gt; , rather than the < and > signs.

So…in the case of your example, you’d type &lt;LIMIT GET&gt; . It’s messed up, but it does work.

William January 21, 2008 at 8:52 am

I did not see this mentioned, I apologize if I am repeating a previous post, but thought you might find it interesting…

One other thing you may wish to consider is a little header trickery. Simply using allow/deny does not effectively hide the files and folders in question. The user will see a 403 Forbidden message. A determined attacker could still gain access to the protected files once that attacker has determined the files exist. Yes, it would be difficult and unlikely, but not entirely impossible. You can more effectively hide these files by adding the following lines outside of the folder section of your .htaccess file:

ErrorDocument 403 whatever/youuse/for404.errors

Then, in your error handling document (guessing you use PHP) add the following line at the top:

header(’HTTP/1.1 404 Not Found’);

To a would-be attacker searching for hidden files, they would not be able to distinguish a blocked area of your site from a folder that does not actually exist. Another benefit is that the content would appear to be non-existent to search engines and other automated processes such as malbots.

Xianhong January 21, 2008 at 7:39 pm

Wordpress should release a security patch for their blog. I used to installed 1 wordpress, i never know that. i will make some changes to the blog.

LoLo January 21, 2008 at 11:19 pm

That bonus tip won’t prevent your version from being leaked. All a person has to do is view the source of any of your feeds to get the same info. Even with FeedBurner cranked up, I can see your category feeds ;-)

Just edit your wp-includes/version.php to change it across the board.

I’d also suggest hiding your entire WordPress install. I just posted info on how to do that along with some other thoughts about your post and put $20 up for grabs for the first person who finds my wp-admin directory.

Allan Stewart January 22, 2008 at 4:01 am

Matt,

This is very useful, thanks very much. Can I add another tip. If you have a dynamic IP you might consider setting up a proxy script from your webserver and then only allow connections to your WP via the IP associated with the proxy script. You should also .htaccess passwd protect the proxy site.

I find this very useful.

Ta

Allan

Peter Westwood January 22, 2008 at 6:07 am

And here’s a bonus tip: in the header.php file for your theme, you might want to check for a line like

<meta name=”generator” content=”WordPress ” />

I’d just go ahead and delete that line or at least the bloginfo(’version’). If you’re running an older version of WordPress, anyone can view source to see what attacks might work against your blog.

You’ll be able to do that with a simple plugin or code in your themes functions.php in the next major version of WordPress – more info on the changes to the WordPress generator generation can be found over on my blog.

Peter January 22, 2008 at 8:17 am
Don Melton January 22, 2008 at 9:21 am

Matt,

Kaloyan K. Tsvetkov is correct that just removing the WordPress version from the header file in your theme does not prevent it from being visible in the style sheet inclusion from the source of the login page.

However, there are other places where the WordPress version is visible. All of your feeds and OMPL file contain the version. And these are not easily removed without modifying the WordPress source files themselves. Also, the “readme.html” file at the root of your WordPress installation contains the major and minor version number, although the specific revision is not there.

Terinea Weblog January 22, 2008 at 4:01 pm

Hey by protecting the wp-admin, does this not stop programs like Windows Live Writer from working?

Jamie

Peter January 22, 2008 at 7:26 pm

Nice article, I just finished my little take on the .htaccess file setup for general security. Besides the Options All -indexes, I also added a few lines to stop browsing the wp-content and wp-include directories.

You can check it out on:
http://blog.avirtualhome.com/2008/01/17/securing-wordpress-part-2/
but make sure you also read the addendum
http://blog.avirtualhome.com/2008/01/22/securing-wordpress-part-2-addendum/

Amit Bhawani January 22, 2008 at 8:22 pm

Excellent tips there matt, especially hiding the plugins page which currently has helped me access my competitors sites and analyze their plugins :D
I have written a complete wordress security guide @ http://www.amitbhawani.com/blog/wordpress-security-guide-securing-your-wordpress-blogs-from-hackers/

Regards
Amit

Matt Cutts January 23, 2008 at 12:15 am

Peter Westwood, that’s great news — thanks! On removing the version number, I know that it stays in places like your feeds, but unless you’re facing a determined attacker (which can happen), often just lowering your profile a little bit makes someone lose interest and move on to an easier target.

Colin Joss January 24, 2008 at 2:04 pm

As I am quite a newbie at wordpress, I really am glad found this article. I don’t think I understand much of it, but doesn’t seem difficult to apply at all.

Colin Joss
East Lothian, Haddington
United Kingdom

Andrei January 25, 2008 at 4:11 am
Ash January 25, 2008 at 12:02 pm

Hi Matt

Thank you for the great tip. My WordPress site was hacked recently and I am going to implement your tips.

Ash

Sherif Elsisi January 25, 2008 at 7:44 pm

Great tips, thanks. I have been trying for a while to find out about security issues with wordpress after being hacked and never came across your tip about hiding you plugins directory. This is a good one!
Most hacks I experienced with my customers sites were due to having the default table prefix installed. I strongly recommend that you add changing the table prefix on your wordpress tables to a difficult one. Wordpress is popular and everyone knows the table names.
To learn more check out http://blogsecurity.net. They did a great job at addressing topics on wordpress security.

Colin Joss January 25, 2008 at 8:29 pm

I just come back again to copy this and apply this on my wordpress..

I can “hide” the plugins, but can’t really put the .htacess right.. How to know or determine the deny IP address? Any criteria?

Thank you

Webguard January 27, 2008 at 9:56 am

I made it easy and protected my /wp-admin dic just with a unusually name and password… i think thats nearly enough in that case

jonathon January 28, 2008 at 1:35 am

i been using this very same protecting for about a year now and have to say it works very well, apart from sometimes block working files.

Files ~ “.(css|jpe?g|png|gif|js|flv|swf)$”

ZAFER January 28, 2008 at 9:34 am

How dow WP work with zen cart?

Singapore SEO January 28, 2008 at 10:43 am

Ah, nice set of tips. Just about to implement it. Anyway, seeing that you love Wordpress alot (I should think you do), any chance Google might just be buying them? :p

Anyway, cant you just deny access to the wp-admin folder except to yourself? I mean, I thought its possible to do that =.= Meh. Sorry for the ignorance :|

Mark January 29, 2008 at 7:43 am

I am having trouble uploading my index.html file into my plugin folder using cPanel.

I am curious about something, Matt, why index.html? Why not index.php?

Peter January 31, 2008 at 4:47 am

Wordpress Security Whitepaper ( downloadable .pdf )

http://blogsecurity.net/wordpress/wordpress-security-whitepaper/

David Dalka January 31, 2008 at 9:42 am

Great stuff. Thanks.

Anuj Seth February 9, 2008 at 9:18 pm

Why not just password protect the directory using .htaccess?

That’s what I’ve done. Wouldn’t that be an easier option to deal with?

Bala Krishna February 19, 2008 at 1:26 am

IP method is good for static IP users.. but not useful with dynamic ip.. however it is great that everybody come up with new ideas to protect blog.. great thanks

Brian March 11, 2008 at 3:20 pm

Thanks for the tip about putting an index.html file into the plugin directory.

Raul March 14, 2008 at 12:28 am

I have included the .htaccess file and it works, it only permits my IP address to access the admin interface, however, my site gets hacked on a daily basis by some robot that I guess searchs for wordpress installations.

I’m using the latest version of wordpress (2.3.3)

Any suggestions?

Many thanks

greggles April 3, 2008 at 6:12 am

What kind of protection does the IP address limitting fix provide? It won’t help CSRF nor XSS based attacks. So…I guess that leaves code execution? Privilege escalation? Can you describe more what you hope to prevent with that?

Paolo May 6, 2008 at 12:39 pm

Thanks for these tips. they are useful!

Firewall Script May 8, 2008 at 6:16 am

Don’t know if you checked out DaveN’s recent post about Firewall script, but i’d really recommend it :)

Halim June 2, 2008 at 10:40 am

If use ip address to block, I suppose it’s not for me because my dynamic ip always changes.

John Colascione June 6, 2008 at 8:59 pm

Thanks for these suggestions Matt. I’ve implemented some of them… It’s a real shame what’s happening with blog, comment, mail system and forum spam lately… It’s really ruining the net and getting out of control…. Like one bad apple spoiling the bunch, just that there’s a whole lot of bad apples falling….

IMGem July 31, 2008 at 11:58 pm

Thanks for tips.

I’ve been looking for ways to secure my wordpress sites. Password protected the wp-admin directory seems more easier than ip restriction.

and i always have a blank index file for wp-content, plugins, themes. it’s just a simple step to make thing safe than regret.

Gary777 August 1, 2008 at 12:40 pm

Matt,

Thanks for the info! I have recently been hit by the Google Malware warning and the cause was a Javascript iFrame hack in my site, I found this post while trying to add security to Wordpress.

I wanted to note to your users that changing the value in wp-includes/version.php to hide your version number can create another issue; if you set this to a version number lower than the current version you will always see the “Version 2.x is now available, please upgrade” in your dashboard.

If you set the version number higher (I.E. 4.9 ) then you won’t see a notice for a new version of Wordpress in your Dashboard, you will have to proactively check for new updates or you will have to sign up for email notices.

Gary777

Mahmoud Abozeid August 17, 2008 at 10:41 am

Awesome tips!
I just did it and everything look great.

Cheers,

- Mahmoud

Toastboy September 25, 2008 at 2:50 pm

I am going to block my wp-admin dir right now. I never even thought of securing that directory to any ip but mine. But it makes sense. I never check my admin from outside my home anyway.

My header showing the version is not going to happen any more either.

Great Site BTW. I am going to read a lot more of your posts.

:-D

John Hoff - eVentureBiz October 26, 2008 at 6:48 pm

Hello Matt. Those are good tips thanks. If it’s ok with you, I have written a 7 post series on securing your WordPress blog and would like to leave the link (feel free to remove my comment if you don’t approve).

It’s a picture-guided step-by-step tutorial for beginners to learn how to secure their blog. The first post is here:
Fluffy’s Guide To Securing Your WordPress Blog – Post 1.

autoambulance November 22, 2008 at 12:25 pm

@ John Hoff

Thanks for the post, but where can we find the rest of your posts?

Michael November 30, 2008 at 6:12 am

I have 5 wordpress blogs. Three of them remember my admin username and password when I log into my admin page. The other two I have to insert my username and password evertime even if I check the box that ask “remember my password?”. Why don’t they remember my username and password like my other three blogs??

Please help. No one seems to know the answer.

Stumped!

Thanks!

Michael

Kevin Cosmi January 20, 2009 at 7:35 pm

Thank you Matt, this is big help for me while i am working and explore using Wordpress Blogs….I realized that this is more useful….

David Kierznowski February 6, 2009 at 2:26 pm

Its great to hear a few guys mentioning our tools over at http://blogsecurity.net.

Check out our free online WordPress vulnerability scanner if you get a chance… a new version has just been released, although, it still needs a lot of work.

Cheers

Connie March 21, 2009 at 3:14 am

Two Questions:
If you exclude IP addresses, how can you write to your blog when you are on the road?

What about the way that IP addresses change, as with some ISPs?

Thanks.

Abhimanyu May 2, 2009 at 10:49 am

Hi, the problem #2 is fixed now in wordpress as it do not show plugins listing. If you are on a dynamic IP, its good not to do #1 step. Although you can use Country IP range.

Abhimanyu
http://mwolk.com

Richard Vanderhurst May 19, 2009 at 3:48 am

A big thanks to this post… I just applied this on my wordpress blogs. Thanks again!

ByREV June 13, 2009 at 4:20 pm

i use mysql random passwd, only localhost in mysal connect, strong admin passwd with 14+ chars/numbers, 777 perm only for cache and uploads folder

btw, for mysql injection search in your site with google this words: wellbutrin, adipex, adderall, xanax, carisoprodol … ex: site:http ://your.site.com xanax

more words here: http://www.mattcutts.com/blog/helping-hacked-sites/ after line “The following is some example hidden text we found at”

Rory Siems July 23, 2009 at 7:45 pm

Hi Matt,

we just spent the day fixing my friend’s wordpress site that apparently had some passthru exploit from a site on a Chinese domain routed through a Russian IP.

We upgraded Wordpress to the latest version, we upgraded all of the plugins to the latest version. The web developer who set up the website claimed that the malicious code installed on the site was not from a Wordpress vulnerability, but rather from a brute force attack on the web host.

I still am not 100% sure that a dictionary attack or brute force attack guessed the password as it was pretty obscure. To be safe I did subscribe to the wordpress development feed. I like the idea of obscuring plugins from snoops too.

Redbrickstock August 20, 2009 at 5:37 pm

Will the .htaccess thing work for a class B address. eg. allow from 64.233.169. ?

doruman August 29, 2009 at 10:26 am

Even if this post has more than a year old, here are very useful informations for any WP blogger. Thank you very much Matt for all that you offer as free informations, not only as Google employer.

Kind regards,
Doru

Russell September 1, 2009 at 6:43 am

Hi Matt
Hope you doing great!
Our blog has been hacked. Im getting all these wierd backlinks to my blog on other blogs but they hidden. My blog developer says “What the script does, apparently, is create those URL’s on their site (that are linking back to you).”

Thought it would interest you. We are working with Godaddy to fix the problem..

Best

Kat Young October 4, 2009 at 7:55 pm

I have had my blog hacked over and over. I will try to edit my .htaccess file thanks =)

Leave a Comment

If you have a question about your site specifically or a general question about search, your best bet is to post in our Webmaster Help Forum linked from http://google.com/webmasters

If you comment, please use your personal name, not your business name. Business names can sound salesy or spammy, and I would like to try people leaving their actual name instead.

You can use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Previous post: How to subscribe to just my Google/SEO posts

Next post: Why cloud services rock