Update:
08/10/07 - Improved methods for allowing Democracy Plugins and better wp-admin code.
16/08/07 - New Rules
A few emails have come through about how user’s WordPress installations have been compromised, or where an attacker has found resources he/she shouldn’t have. This article will discuss some security techniques to better harden and secure your WordPress blog; this is especially effective in a hosted environment.
Let me start by saying this guide may not be for everyone, and chances are that it may break some third party plugins and templates.
It is not all doom and gloom; if you are able to use this guide it will significantly increase the security of your blog. It will prevent many attacks including brute force attacks, plugin enumeration, directory listings, sensitive information disclosure and file include vulnerabilities. Additional hardening guides will be required for different circumstances, so if this is not for you let us know so we can plan additional guides to meet user requirements.
Important Note: Please ensure that your WordPress files and database are backed up before attempting any of these changes.
Using htaccess <files> directive, we can restrict all files accept images, CSS and JavaScript. The .htaccess file will look as follows:
Order Allow,Deny Deny from all <Files ~ "\.(css|jpe?g|png|gif|js)$"> Allow from all </Files>
If we want to allow certain plugins such as Democracy, we can append the following to our wp-content/.htaccess file:
<Files "democracy.php"> Allow from all </Files>
Put this into your .htaccess file within your wp-content and wp-includes directories. As a side note, you can also allow specific files to get your plugins and/or templates to work, if needs be. This is a much cleaner method to do it then discussed in a previous version of this document.
If you got through that, well done.
Now to restrict wp-admin you have two choices. Put a .htaccess file into your wp-admin directory with one of the two choices below.
You can resrict it by IP:
order deny,allow allow from a.b.c.d # This is your static IP deny from all
The above code will prevent browser access to any file in these directories other than "a.b.c.d" which you should change to be your static IP address.
OR restrict the directory with a password:
AuthUserFile /etc/httpd/htpasswd AuthType Basic AuthName "restricted" Order Deny,Allow Deny from all Require valid-user Satisfy any
OR improved version:
There is a bug where the above rules will cause a password box to appear to the user if they submit a comment without an e-mail address. This occurs, because some CSS and image files are located inside the wp-admin directory. To get around this we can wrap the above rule set in a file directive which disallows .PHP files but permits the rest. This still prevents alot of direct attacks and also provides alot of additional features.
<Files ~ "\.(php)$"> AuthUserFile /etc/httpd/htpasswd AuthType Basic AuthName "restricted" Order Deny,Allow Deny from all Require valid-user Satisfy any </Files>
Thats it! you now have a more secure blog and hopefully everything still works for you.
This article was written by David Kierznowski for BlogSecurity. Read some of his other articles:
Thanks to Dustin Rue for pointing out some cleaner methods of doing things.
Another way to protect your blog is to use .htaccess and .htpasswd. As this isn’t nearly as secure as the Option with access only for a special IP or IP range. It’s only recommend to use if you have no Mod_rewrite available. Anyway .htpasswd isn’t weak, at least it isn’t if you’re creative and use some uncommon Username and a strong password.
Here’s a link to an howto: informations:http://www.euronet.nl/~arnow/htpasswd/documentation.html
[…] BlogSecurity » Hardening WordPress with mod_rewrite […]
Was not able to implement these instructions because the style sheet is not called out in a a strightforward way. In header.php the callout looks like this:
@import url( );
I looked around some for definitions of either ‘bloginfo’ or ’stylesheet_url’ with no success. They must be buried somewhere deep in either the theme or (worse) WP itself. WP version 1.5, alas, and I have no access to upgrade it.
Me again. The comment code ate the relevant line. I’ll try reproducing it below with spaces so maybe it will sneak through the draconian filters:
Nope, ate it again, giving up. Forum moderators: email me for the suppressed code.
Thanks for this article, I came to this article after using wp-scanner. I made all the steps, but I can’t protect this folders because many plugins fails :-(
Daniel, I know it can be really annoying cant it! Don’t despair there are other ways which we’ll discuss in future articles. Using wp-scanner will atleast help you resolve any obvious security holes. Thanks for your feedback.
Since I don’t have a static IP I guess this hint is useless for me, hmm…?
Alter, the only access you need is to the wp-admin directory. So restricting access to both wp-includes and wp-content is much more secure. Also, you can restrict your wp-admin directory by an IP range if you like, rather then by a single IP address.
[…] dem man seine Wordpress-Installation auf Lücken testen kann, sowie ein Artikel, wie man die Installation ziemlich dicht machen […]
[…] Hardening WordPress with mod_rewrite […]
[…] BlogSecurity » Hardening WordPress with mod_rewrite wordpress kemenyites. :-) (tags: wordpress security mod_rewrite harden) […]
[…] anderen habe ich einen Tip von BlogSecurity umgesetzt und für einige Verzeichnisse den direkten Zugriff verboten. Das macht WordPress dann […]
What about uploaded images? Is there a way to select another directory besides /wp-content/uploads/, or should I just not use the built-in uploader?
Yes, this can be changed under wp-admin. However, I would suggest reading our Role Management article, to provide a little more security here.
Awesome! Thank you. And I downloaded that plugin. Every time I set up a WP blog for someone, I always make sure to explain to them the importance of having a second account for day-to-day activities.
One more question: Your tool showed me four or five areas where the version was leaked. How do I go about hiding that in non-theme files? Is there a plugin or hack that strips that information? Or do I have to edit those files after each upgrade?
Would it be easier to password protect these directories to prevent attackers and if so, how secure would this alternative method be?
I did this before but I removed the password protection when I upgraded Wordpress and haven’t got round to doing it again.
Maybe I should.
So I tried this lil tip for all 3 dir and this is what I found:
wp-admin:does not work…internal server errors
wp-includes: seems not to break anything
wp-content: breaks plugins…editormonkey for one…
When you say “my IP” I assume you mean the web servers IP address.
Jon, thanks for the positive feedback.
Regarding removing the version, there are three ways I can think of to do this but I really don’t want to recommend any of them publicly. Between me and you, removing it manually is the best approach for the time being.
Anthony, its an interesting question. The reason I prefer the method detailed in this article, is because the attacker doesn’t even know these directories exist. The password method, may tempt the attacker to dig deeper.
Dave, the internal server error is probably due to an error in your .htaccess file. As for wp-content, unfortunately, some plugins may require tweaking to get them working with this solution.
The IP referred to is the IP you will be using to access your wp-admin directory, not your web server IP.
Thanks for your questions Dave.
[…] das Thema Sicherheit von Wordpress-Installationen. Diese Tips zum Abdichten der Weichware auf BlogSecurity habe ich gerade mal hier umgesetzt, anscheinend funktioniert noch alles wie zuvor, was ja schon mal […]
These are some good, basic steps that should be default for any blog install, IMO - but I would recommend an even more powerful option: mod_security. As an Apache module, mod_security provides far more protection over what people are trying to post to your blog, over htaccess, which just locks down access to a sane level. Not that the htaccess is a bad suggestion, it’s a start, and should be done, but after that, install mod_security, and watch the logs fill up with crappy post attempts trying to do some XSS, mysql inserts and more…
fak3r, mod_security can be useful but it may not suit everyones needs, especially in shared hosting environments. However, we do have these articles in the pipline, great comments.
Is it possible that the procedure breaks the incoming pingbacks functionality?
I’m not receiving any pingbacks, but I’m not sure if it is due to hardening the wp-install with the htaccess as mentioned here…
thx
Tom
Tom, its possible but BlogSec uses similar techniques and we have not had this problem.
David, thanks for the fast reply.
Hi David, Love this post! Have you heard of the new WordPress plugin that password protects /wp-admin/ for you automatically? I got some great ideas from this article thank you!
@AskApache
AskApache, no problem. These ideas can certainly be implemented into a plugin. Keep us posted on its development.
[…] As a side note, if you want the easiest way to password protect your wp-admin directory you can use this plugin by askapache or if you prefer to do it using the manual way … you can check blogsecurity website […]
[…] Sept. 5, 2007: Follow these instructions at BlogSecurity to create an .htaccess file that restricts wp-content and wp-includes, and restricts access to […]
Hi. Thanks for the instructions — they worked great for me. A possible change for your wp-content .htaccess: add “xsl” as an extension. Not a big deal, but the xml sitemap generator has an option to use an xslt stylesheet, which is kept in wp-content. I got an error before adding the xsl.
(To clarify: the error was just in viewing the sitemap.xml. It’s in the root of the web site, but needs to pull the .xsl from wp-content. The plugin worked fine either way. So again — not important, just a small detail for people that might have this plugin.)
[…] little while back, I took to using the wonders of .htaccess directives to make my WordPress deployments more secure. It does work but has the disadvantage that desktop blog editors like Windows Live Writer, Word […]
[…] Restrict access to those directories or files as explained in Hardening WordPress with .htaccess. […]
Just a note:
the htaccess method as described above for the wp-include directory will break the build-in wysiwyg editor. Since I normally don’t use the wysiwyg thingie I haven’t noticed this for a while.
————————-
Order Allow,Deny
Deny from all
Allow from all
Allow from all
————————-
should do the trick.
^– oops, it stripped all the code :-)
a new rule should be added to the htaccess file:
Order Allow,Deny
Deny from all
(Files ~ “js/tinymce/*.$”)
Allow from all
(/Files)
[…] The risk is mitigated for those readers who implemented our ideas in BlogSec’s Hardening WordPress article. […]
[…] Hardening WordPress with .htaccess […]
Another issue I just found out about with the htaccess in wp-admin:
if a comment misses a valid email or the content is left out, wp-comment-post.php will call the worpress-logo and some css file from inside the wp-admin directory. so the user ends up with the htpass prompt. this only occures if the “please fill in all fields” error-page is displayed via the wp-comment-post.php.
[…] den Wordpress Hardening von blogsecurity.net befolgt hat aber trotzdem TinyMCE als Editor benutzen möchte, der sollte noch […]
[…] More information on this can be found at:http://blogsecurity.net/wordpress/article-210607/ […]
With the above .htaccess the WP-Scanner still thinks I’m unsave: “WordPress directories accessible (wp-content).”
But accessing the directory gives a 403 Forbidden, so what’s being checked?
BOK, probably a bug, I’ll make a note and check it out for the next release. Thanks buddy.
[…] We have released a newer version of our popular Hardening WordPress with htaccess guide. […]
I have to agree with BOK message from 31. October. I have the same problem (and this is long lasting issue, iirc).
Unfortunately the WP-scanner doesn’t tell which directories *specifically* are accessible. I don’t have anything special installed, just a few basic plugins and some themes…
By the way, after installation of AskApache password protection plugin, the wp-scanner complains about the file .aahtpasswd in the root of the web presentation (it’s its default location; it is reported as a dangerous file). Renaming it and moving elsewhere solves the problem - byt why did it complain in the first place?
I wouldn’t worry about the wp-content issue, it’ll be resolved in the next release.
The .aahtpasswd file will contain your username and password, hence the dangerous file warning.
Thanks for your feedback.
[…] Security Updates Hardening WordPress: Blog Security has updated it’s Hardening WordPress with htaccess with more tips and information to help you keep your WordPress blog […]
[…] BlogSecurity ” Blog Archive ” Hardening WordPress with htaccess (tags: wordpress security htaccess mod_rewrite apache blog bloggin) […]
[…] your wordpress plugins, hardening wordpress, almost perfect .htaccess file for wordpress blogs, , hardening wordPress with .htaccess, & things i do to optimize and secure every wordpress site and […]
[…] Restrict access to the wp-content, wp-includes & wp-admin directories. […]
I can understand why this could be a huge problem for some folks but us basic folks who just have “basic” sort of blogs - why would we need to worry? What might someone want to do to a blog that might have some cool photos or something but nothing that really needs to be secure?
Perhaps this sounds like a silly question but I’m wondering if I really need to make these files and perhaps run into problems because of them.
Thought? Thanks for the post David.
Peace, love and understanding.
~ RS ~
RubyShooZ, everyone who runs a special Software or Softwareplugin is a potential target. Many of the intrusion tries are done through Bots, and these don’t care about your PageRank or whatever(they just search and try their exploits). So that’s the reason why you could be a target as well. Next if you can live with the possibility to help Spammers, Cracker or whatever you don’t need to do anything, although you risk to loose your Blog work. So if you apply our tips you don’t only protect your Blog against a wide bunch of known exploits as well as mostly against many unknown ones. You could compare like your house, if you feel save in the current state, fine. But after the first burglar you don’t do so anymore and want to add some protection to your house. We suggest you to add the protection to you r house before the first burglar was in. We try to help to make your house as safe as possible with the smallest possible(or no) loss of comfort.
Hope that helped, to understand what our aim is.
A very nice plugin and very useful.
RubyShooZ, I am an eensy, weensy, site — off the grid and virtually invisible. However, on December 21 my WP site was defaced. It was a brand new install and not yet complete, so I simply erased it all and will start over. The culprit wasn’t a pig and didn’t leave any smut or do any gross damage. He/she just replaced my blog header with their own, which means they got into my WP admin panel. Visits by a strange ‘bot preceded the actual defacement, which may itself have been done by a ‘bot, and not by some wild-eyed psychotic.
The people that design extreme software, like spiders and ‘bots, aren’t cruising the web bent on wrecking havoc. Their thrill is in observing their cunning little monster. They may be vaguely aware of other humans about them, but we are inconsequential when it comes to their personal entertainment.
Their crawlers strike targets of opportunity. It is our business then to remove ourselves from the realm of easy pickin’s.
Thanks John for sharing your experience, the positive aspect on your damage was that it happened in some early stage, and therefore didn’t caused much harm. But it makes you more aware about this thematic, and should give Ruby some good example that as well nearly useless Blogs( like yours was in the current state) can become the aim of cracker, and Bots. So it’s for sure nothing which only PowerBlogger faces.
Webrocker on 10 September, 2007 at 8:11 pm #
Just a note:
the htaccess method as described above for the wp-include directory will break the build-in wysiwyg editor. Since I normally don’t use the wysiwyg thingie I haven’t noticed this for a while.
————————-
Order Allow,Deny
Deny from all
Allow from all
Allow from all
————————-
should do the trick.
Webrocker on 10 September, 2007 at 8:13 pm #
^– oops, it stripped all the code :-)
a new rule should be added to the htaccess file:
Order Allow,Deny
Deny from all
(Files ~ “js/tinymce/*.$”)
Allow from all
(/Files)
======
This is a serious problem in wordpress. i am not using the standard build in editor and now it is blogged. so what else would i have to allow if im not using the tiny editor?
[…] Hardening WordPress with .htaccess […]
AuthUserFile /etc/httpd/htpasswd
AuthType Basic
AuthName “restricted”
Order Deny,Allow
Deny from all
Require valid-user
Satisfy any
==
will cause customer cant login, because the popup field doesnt appear. is there a workaround?
code was cut. this causes the problem (Files ~ “.(php)$”)
i figured it out: when “domain.com/wp-admin/” the popup window for login doesnt appear. if “domain.com/wp-admin/INDEX.PHP” everything works right. be ahed!!
[…] Update: 2008-01-24: damned, again, I read some stuff, updated some aswell (Hardening WP) […]
[…] Để an toàn hơn, bạn có thể khóa luôn thư mục WP-Inclues và WP-Content, tham khảo chi tiết tại đây. […]
[…] Để an toàn hơn, bạn có thể khóa luôn thư mục WP-Inclues và WP-Content, tham khảo chi tiết tại đây. […]
hi, in the *improved version*, shouldn’t the first line read:
instead of:
??
[…] Để an toàn hơn, bạn có thể khóa luôn thư mục WP-Inclues và WP-Content, tham khảo chi tiết tại đây. […]
[…] Để an toàn hơn, bạn có thể khóa luôn thư mục WP-Inclues và WP-Content, tham khảo chi tiết tại đây. […]
[…] Hardening Wordpress with htaccess […]
I am using your Step one:
“Order Allow,Deny
Deny from all
Files ~ “\.(css|jpe?g|png|gif|js)$”
Allow from all
/Files
Need to include a plugin
“extended-live-archive.php” it is in the subfolder
“plugins/extended-live-archive/”
what do I have to add to the htaccess?
thanks
a small extension of Mirko’s question. i am trying to get this running for quite some time now, but to no avail.
i have the following htaccess file in wp-include (the brackets were replaced to avoid problems with posting)
Order Allow,Deny
Deny from all
(Files ~ “\.(css|jpe?g|png|gif|js)$”)
Allow from all
(/Files)
(Files ~ “js/tinymce/*.$”)
Allow from all
(/Files)
this is how i understand the instructions above. unfortunately, it doesn’t work! the tinymce does not start!
when new advanced-tinymce plugin is used, it is probably necessary to do similar thing for the contents/plugins/advanced-tinymce, since it requires access to some php/htm files in that directory. similarly, i was not able to get it working using the procedure above.
both problems i solved by adding extra htaccess file to the respective directories, allowing pictures, js, php, and htm files to be accessed. but i don’t find it very robust - i’d prefer having it in the files in wp-include and wp-contents directly…
would anybody please help?
thanks!
lubos
When I put the improved wp-wdmin htaccess into the directory as instructed, instead of getting a prompt for a password, I get a “nothing found for” error. Specifically: Sorry, no posts matched your criteria.
[…] Để an toàn hơn, bạn có thể khóa luôn thư mục WP-Inclues và WP-Content, tham khảo chi tiết tại đây. […]