Spring Sale! Save 30% on all books w/ code: PLANET24
Web Dev + WordPress + Security

Secure Visitor Posting for WordPress

Normally, when visitors post a comment to your site, specific types of client data are associated with the request. Commonly, a client will provide a user agent, a referrer, and a host header. When any of these variables is absent, there is good reason to suspect foul play. For example, virtually all browsers provide some sort of user-agent name to identify themselves. Conversely, malicious scripts directly posting spam and other payloads to your site frequently operate without specifying a user agent. In the Ultimate User-Agent Blacklist, we account for the “no-user-agent” case in the very first directive, preventing a host of anonymous visitors from hitting the site.

In addition to empty user-agent strings, malicious requests for site content frequently fail to provide any referrer information. Unless special privacy software is being used, the web page from which a visitor has arrived at your site will be specified in the header information for that request. Likewise, when a visitor posts a comment at your site, the referrer string for that post request will be the URL of that particular page. Thus, as with blank user-agent requests, no-referrer requests are frequently indicative of spam and other malicious behavior.

Another important piece of information provided by all legitimate clients is the host request header. The host header specifies the Internet host and port number of the requested resource. This information is required for all clients making HTTP/1.1 requests. Thus, requiring the host request-header field for all posts to your site safely eliminates illicit requests from hitting your server.

By targeting these three circumstances — blank user agents, empty referrers, and missing host headers — we can greatly improve the overall security of our WordPress-powered sites. Our weapon of choice to forge this server-side strategy is custom set of HTAccess (or httpd.conf) directives:

# WORDPRESS POST SECURITY
<IfModule mod_rewrite.c>
 RewriteEngine On
 RewriteCond %{REQUEST_METHOD}  POST
 RewriteCond %{HTTP_REFERER}    !.*perishablepress\.com [NC]
 RewriteCond %{REQUEST_URI}     !.*(wp\-login|wp\-admin|wp\-content|wp\-includes|wp\-trackback).* [NC]
 RewriteCond %{HTTP_USER_AGENT} ^-?$ [OR]
 RewriteCond %{HTTP_REFERER}    ^-?$ [OR]
 RewriteCond %{HTTP_HOST}       ^-?$
 RewriteRule ^(.*)$ - [F,L]
</IfModule>

To implement this HTAccess strategy, replace the domain from “perishablepress.com” to the name of the domain on which these directives operate. To allow multiple domains, replicate the second directive as follows:

RewriteCond %{HTTP_REFERER} !.*domain-01\.tld [NC]
RewriteCond %{HTTP_REFERER} !.*domain-02\.tld [NC]
RewriteCond %{HTTP_REFERER} !.*domain-03\.tld [NC]

After specifying the correct domain information, simply place the code into your site’s root HTAccess file and test for proper functionality. The code itself should be clear, but if something needs explained, please drop a comment and I will do my best to break it on down. And finally, a few obligatory disclaimers:

  • This code works on my server. No guarantees that it will work on yours
  • Blocking blank user agents may result in a small % of false positives
  • Blocking empty referrers may result in a small % of false positives

While this security technique won’t stop all of the bad guys, it will certainly help keep out some of the more obvious offenders. Protecting your site against malicious post requests is an important part of any serious security strategy. Thanks to the magical powers of Apache’s HTAccess directives, we now have a method to secure visitor posting to your WordPress-powered site.

About the Author
Jeff Starr = Web Developer. Security Specialist. WordPress Buff.
SAC Pro: Unlimited chats.

25 responses to “Secure Visitor Posting for WordPress”

  1. Jeff, I’m currently using this in my htaccess:

    # Block Comment Spam
    RewriteEngine On
    RewriteCond %{REQUEST_METHOD} POST
    RewriteCond %{REQUEST_URI} .wp-comments-post\.php*
    RewriteCond %{HTTP_REFERER} !.*MYWEBSITE.com.* [OR]
    RewriteCond %{HTTP_USER_AGENT} ^$
    RewriteRule ^(.*)$ ^http://%{REMOTE_ADDR}/$ [R=301,L]

    Can the htaccess rules in your post be added to what I already have or should they be used instead of what I currently use.

    Thanks!

  2. Jeff Starr 2009/06/02 8:11 am

    Hi Myra, either strategy should work fine — the rules should not interfere with one another, so they may be used together in the same HTAccess file, or you may simply replace your existing “Block Comment Spam” method with the directives provided in the article.

    Whereas your method essentially is saying, “block any post requests for wp-comments-post.php that don’t come from my site or have a blank user agent,” my method works a bit differently by saying, “block any post requests whatsoever (for any file not whitelisted in the next line) from blank user-agents, referrers or hosts that are not from my site.”

    The central difference here in regards to the wp-comments-post.php file is that my code is only blocking blank user agents, referrers, and hosts, whereas the code you are using is blocking everyone except your site as the referrer, or anyone with a blank user agent. Thus using both methods provides more protection than using either one alone.

  3. Thanks for the clarification Jeff. Now I have another question. I see your whitelist includes wp-admin and wp-login. Shouldn’t we want to block wp-admin and wp-login files from blank user-agents, referrers or hosts?

  4. Jeff Starr 2009/06/03 9:39 am

    Hi Myra, yes the whitelist includes wp-admin and wp-login, but these files may be removed from the list if you are certain that no users, plugins, or associated scripts require access. For example, many blogs (such as this one) allow users to register and perform various tasks in the WordPress Admin area. Whitelisting the admin files ensures that these visitors retain access even when visiting anonymously. If your site does not allow visitor registration and/or Admin access, then you may remove these items from the whitelist. If you experience any functional issues after doing so, simply put them back in.

  5. Thanks again, Jeff.

  6. I loaded this one my site (VizWorld.com), works great. However, one thing to note: It breaks WordPress’s iPhone App. I guess some xmlrpc file needs to be whitelisted ?

  7. Cool blog and thanks for the tips!

  8. Jeff Starr 2009/06/07 6:05 pm

    @Randall: Yes, that may be the case. Try replacing the whitelist values to this:

    !.*(xmlrpc\.php|wp\-login|wp\-admin|wp\-content|wp\-includes).* [NC]

    Let me know how it goes! :)

  9. b7ral7nen 2009/07/05 8:17 am

    Thanks Jeff.

  10. Phil Hollows 2009/08/01 4:33 pm

    Blocking on an empty referrer is a dangerous strategy – desktop RSS readers and email clients rendering HTML will not have a referrer when visitors click through, and since they won’t be coming at you from a page online, surely you risk blocking legitimate users with this technique? What if someone clicks a comment link in their RSS reader or email? There won’t be a referer unless they’re using a webmail service.

  11. Jeff Starr 2009/08/01 6:01 pm

    Hi Phil, like with many security strategies, blocking empty referrers is a bit of a trade-off. On the one hand, yes, you might be blocking a percentage of legitimate visitors, but on the other hand, you are blocking all of the scumbags out there using an empty referrer to attack your site. It is up to the administrator to decide which side of the equation is more important.

  12. Phil Hollows 2009/08/03 4:54 am

    Hi Jeff:

    Completely agree – just wanted to make sure that folks are fully aware that the potential for collateral damage extends to legitimate readers via RSS and email, i.e. beyond the bad guys.

    Cheers,

    Phil

Comments are closed for this post. Something to add? Let me know.
Welcome
Perishable Press is operated by Jeff Starr, a professional web developer and book author with two decades of experience. Here you will find posts about web development, WordPress, security, and more »
Blackhole Pro: Trap bad bots in a virtual black hole.
Thoughts
I live right next door to the absolute loudest car in town. And the owner loves to drive it.
8G Firewall now out of beta testing, ready for use on production sites.
It's all about that ad revenue baby.
Note to self: encrypting 500 GB of data on my iMac takes around 8 hours.
Getting back into things after a bit of a break. Currently 7° F outside. Chillz.
2024 is going to make 2020 look like a vacation. Prepare accordingly.
First snow of the year :)
Newsletter
Get news, updates, deals & tips via email.
Email kept private. Easy unsubscribe anytime.