Protect WordPress Against Malicious URL Requests

by Jeff Starr on Tuesday, December 22, 2009 64 Responses

A few months ago, many WordPress sites were attacked with some extremely malicious code. While searching for a good solution, I discovered the following gem of a plugin in the pastebin repository:

<?php /* Plugin Name: Block Bad Queries */

if (strlen($_SERVER['REQUEST_URI']) > 255 || 
	strpos($_SERVER['REQUEST_URI'], "eval(") || 
	strpos($_SERVER['REQUEST_URI'], "base64")) {
		@header("HTTP/1.1 414 Request-URI Too Long");
		@header("Status: 414 Request-URI Too Long");
		@header("Connection: Close");
		@exit;
} ?>

This script checks for excessively long request strings (i.e., greater than 255 characters), as well as the presence of either “eval(” or “base64” in the request URI. These sorts of nefarious requests were implicated in the September 2009 WordPress attacks.

To protect your site using this lightweight script, save the code as a plugin and activate in the WordPress Admin area. Once active, this plugin will silently and effectively close any connections for these sorts of injection-type attacks.

For further protection against malicious code, automated attacks, and other cracker nonsense, check out my 4G Blacklist.

Update to original method

As is often the case, Perishable Press readers have helped to improve this plugin by leaving comments, asking questions, and recommending changes. Here is the new, recommended version of the plugin:

<?php 
/* 
Plugin Name: Block Bad Queries
Plugin URI: http://perishablepress.com/press/2009/12/22/protect-wordpress-against-malicious-url-requests/
Description: Protect WordPress Against Malicious URL Requests
Author URI: http://perishablepress.com/
Author: Perishable Press
Version: 1.0
*/
global $user_ID; if($user_ID) {
	if(!current_user_can('level_10')) {
		if (strlen($_SERVER['REQUEST_URI']) > 255 || 
			strpos($_SERVER['REQUEST_URI'], "eval(") || 
			strpos($_SERVER['REQUEST_URI'], "CONCAT") || 
			strpos($_SERVER['REQUEST_URI'], "UNION+SELECT") || 
			strpos($_SERVER['REQUEST_URI'], "base64")) {
				@header("HTTP/1.1 414 Request-URI Too Long");
				@header("Status: 414 Request-URI Too Long");
				@header("Connection: Close");
				@exit;
		}
	}
} ?>

The changes include, in order, proper plugin declaration (thanks Aldo), exclusion of admin pages, and additional protection against CONCAT and UNION+SELECT requests (thanks John Hoff).

Merry Christmas!


64 Responses

Add a comment

[ Gravatar Icon ]

Alex Denning#1

Great tip Jeff. Thanks for that. Going into my framework :)

[ Gravatar Icon ]

Eric B.#2

Very useful security tip. Thanks for sharing!

[ Gravatar Icon ]

Indrek#3

Thanks a lot for this plugin. You can never have a too secure blog so this is definitely going to be added on mine.

[ Gravatar Icon ]

Rick Beckman#4

Even better, just add it to the top of wp-config.php. It’s loaded before plugins are (I think), so handling as much security as possible there cuts down on the amount of processing that needs to be done to handle invalid/malicious requests.

It also keeps the plugin panel clean. :D

[ Gravatar Icon ]

Aldo#5

Merry Christmas, Jeff, and thanks again for your precious posts. :-)

[ Gravatar Icon ]

Lillan#6

Useful indeed! Tnx :)

[ Gravatar Icon ]

Thomas Scholz#7

Most attackers try to load some external scripts into the page. My double slash fix (http://toscho.de/2009/wordpress-2-8-3-das-doppelslash-problem/) has a nice side effect here: it makes all URLs in GET parameters invalid.

@Rick Beckman: If you call this code before WordPress has fixed the broken REQUEST_URI on IIS it won’t work there.

[ Gravatar Icon ]

Rick Beckman#8

I was unaware that WordPress did any fixing of URLs for IIS’ sake. If that’s the case, then the plugin would be better — or emulating the fix in the security code, if it’s concise enough to copy/paste easily.

[ Gravatar Icon ]

Greg#9

Nice one

the too long request limit could be done via htaccess with something like this:

RewriteCond %{REQUEST_URI} ^(.*){255,} [NC]
RewriteRule - [R=414,L]

I bet…?

Just wonder if this is not implemented by default on apache?

[ Gravatar Icon ]

JP#10

Is this something everyone should implement, or are only pre-WP 2.9 blogs vulnerable?

[ Gravatar Icon ]

tcg#11

I could be wrong, but I’m pretty sure this may break a couple of cases:

For instance, if I’m using permalinks that contain the article title, and my article was called “About Base64″, by default Wordpress would use something like “about-base64” as the slug for my post.

If someone tries to visit that page, doesn’t that put the string “base64” somewhere in the Request URI?

Just wondering/noting.

[ Gravatar Icon ]

Sebastian#12

If you plan to do any bulk management of your posts, I’d recommend putting this code inside

if(!is_admin()) { /* your code here */}

[ Gravatar Icon ]

Yael K. Miller#13

I’m a little confused with that to do with this. Is the below correct?

  1. paste code into new file
  2. save as blockbadqueries.php
  3. upload to wp-content/plugins
  4. will appear in dashboard as a plugin - activate it.
[ Gravatar Icon ]

Jeff Starr#14

Thanks everyone for the great feedback on this post. To respond to a few of the questions:

@Greg: Good call. Perhaps not set by default on Apache, but custom-configured on certain servers. Btw, is {255,} proper syntax? Looks odd..

@JP: As far as I know, WordPress fixed the vulnerability in the Admin area, but I don’t think it protects against the malicious URL requests blocked in this plugin.

@tcg: yep, if you plan on blogging about Base64, you’ll need a conditional statement in there to allow for the permalink. Fortunately (or unfortunately, depending on how you look at it), Base64 is a rather rare topic for blog posts ;)

@Sebastian: Good idea :)

@Yael K. Miller: yes, that is exactly correct. And once the plugin is activated, nothing else needs to be done. It works quietly in the background to block the bad guys. “Fix it and forget it,” as they say.

[ Gravatar Icon ]

Greg#15

@Jeff Starr Hi Jeff, as you said yourself:

a{n,} specifies n or more of the preceding character. e.g., x{3,} matches three or more x’s.” so I presume that: if I match “whatever” with the “^(.*)” and set the max number or more with {255,} (comma mean “or more” here) it could be ok.

My own server is restrict by 36 characters for a filename, so you probably right, this is apache related, because unix by default is set to 255…but this doesn’t mean there’s a limit for the uri.

I’m testing more of that stuff and give feedback asap. :)

[ Gravatar Icon ]

John Hoff - WP Blog Host#16

Excellent tip, Jeff. One question though.

It looks as if your 4g Blacklist already does this through .htaccess. Is that not true?

Thanks

[ Gravatar Icon ]

Jeff Starr#17

Hi John, Good question.. The 4G Blacklist does not target either of these requests specifically, but it does block most of the junk that is used within these types of requests. I.e., if you are using the 4G Blacklist, this plugin is probably overkill, but certainly won’t hurt your security efforts ;)

Also, the upcoming 5G Blacklist will block these requests specifically.

[ Gravatar Icon ]

John Hoff - WP Blog Host#18

Jeff, could this code be altered to include such strings as CONCAT and UNION+SELECT?

[ Gravatar Icon ]

Shay Howe#19

Jeff you have some amazing articles and this one is no exception. This is a great plugin, thank you for your forward thinking!

I did however experience one issue. Using this plugin causes the included WordPress jQuery file (../wp-includes/js/jquery/jquery.js) to stop working properly. I rely on the included jQuery file for a few features on my website and when I added your plugin those features stopped working. Instead I started getting the “Request-URI Too Long” error.

Just a heads up, thanks again for your good work!

[ Gravatar Icon ]

Jeff Starr#20

@John Hoff: Yes of course - perhaps something like this would do it:

<?php /* Plugin Name: Block Bad Queries */

if (strlen($_SERVER['REQUEST_URI']) > 255 ||
       strpos($_SERVER['REQUEST_URI'], "eval(") ||
       strpos($_SERVER['REQUEST_URI'], "CONCAT") ||
       strpos($_SERVER['REQUEST_URI'], "UNION+SELECT") ||
       strpos($_SERVER['REQUEST_URI'], "base64")) {
              @header("HTTP/1.1 414 Request-URI Too Long");
              @header("Status: 414 Request-URI Too Long");
              @header("Connection: Close");
              @exit;
} ?>

[ Gravatar Icon ]

Jeff Starr#21

@Shay Howe: Thanks for the heads up! Not sure why that might be happening in your case, but perhaps an equivalent htaccess method would work instead?

[ Gravatar Icon ]

Shay Howe#22

@Jeff Starr: Thanks for your suggestion, I appreciate your help. I tried dropping it into my .htaccess file via:

RewriteCond %{REQUEST_URI} ^(.*){255,} [NC]
RewriteRule - [R=414,L]

This still blocked the jQuery file and also through off my CSS file. I tried using your 4G Blacklist as well and encountered the same issue with the jQuery file.

I’ll play with this a little more and let you know if I am able to get it working correctly. Thanks Jeff!

[ Gravatar Icon ]

Aldo#23

Helpful plugin, as I wrote before, but it doesn’t allow operations as, for example, making a bulk/mass edit of posts.

I was editing a couple of posts by adding a tag: the result was a blank page. Looking at the address bar and the long URL, I instantly realized that this plugin doesn’t allow such URLs. I deactivated it and was able to make the bulk edit.

[ Gravatar Icon ]

Jeff Starr#24

Hi Aldo, assuming we can safely allow long query strings in the WordPress Admin area, we can do something like like this:

<?php /* Plugin Name: Block Bad Queries */

if (!current_user_can('level_10')) {
       if (strlen($_SERVER['REQUEST_URI']) > 255 ||
              strpos($_SERVER['REQUEST_URI'], "eval(") ||
              strpos($_SERVER['REQUEST_URI'], "base64")) {
                     @header("HTTP/1.1 414 Request-URI Too Long");
                     @header("Status: 414 Request-URI Too Long");
                     @header("Connection: Close");
                     @exit;
       }
} ?>

This should allow you to do everything you normally do in the Admin area (mass-editing of posts, etc.), while still protecting the external site from attacks.

[ Gravatar Icon ]

Aldo#25

Hi Jeff, right! :-)
Thanks!

This plugin should go in the wordpress repository.

[ Gravatar Icon ]

Yael K. Miller#26

Jeff, what’s your recommendation for use? The plugin you gave in the post or what you left in comment #24 ?

[ Gravatar Icon ]

Jeff Starr#27

Yael, go with the plugin given in comment #24. I need to update the post with the improved code.

[ Gravatar Icon ]

John Hoff - WP Blog Host#28

I tried the one in #24 and it gave me a fatal error on my blog.

If you’re going to use that one, maybe test it a couple times.

For now, the code in #20 does well for me. Thanks, Jeff.

[ Gravatar Icon ]

Jeff Starr#29

The post has been updated with better code. The new version allows for long URIs in the Admin area, blocks two additional request strings, and should work in all versions of WordPress. Please use the new plugin instead, especially if you experienced issues with the previous version.

[ Gravatar Icon ]

John Hoff - WP Blog Host#30

Thanks for the mention, Jeff. Also, the new updated code did not give me a fatal error … works like a charm!

Thanks again.

[ Gravatar Icon ]

Rod Homor#31

Nice! I always appreciate folks willing to share ideas for keeping WordPress as safe as possible, b/c these days, who doesn’t have a client project running on WP??

Thanks!

[ Gravatar Icon ]

elcidi#32

This is very much helpful to increase the security.
Many thanks foe sharing it

[ Gravatar Icon ]

Jauhari#33

I will install on my Blog ;)

[ Gravatar Icon ]

cubus#34

Wouldn’t it be possible to include this in the functions.php file of your wordpress (framework) theme?
That way I don’t have to think of including it as a plugin in every wordpress set-up I do.

[ Gravatar Icon ]

Rick Beckman#35

Yes, that should work, cubus. I prefer to do all sorts of customizations via my theme’s custom functions file (either that or directly to the wp-config.php file, just for kicks).

[ Gravatar Icon ]

ikram#36

thanks. very usefull

I will use it on my blog

regards

[ Gravatar Icon ]

r-a-y#37

Great code.

Just wondering if, in certain scenarios, a permalink can be longer than 255 characters.

I can think of a weird example where there’s a bunch of recursive sub-categories and a long %postname%.

This is if someone is using /%category%/%postname%/ as their permalink structure.

[ Gravatar Icon ]

Jeff Starr#38

@r-a-y: I’m sure that is a possibility, but I have never actually seen a permalink that long before. It’s a good heads up for others though: if your site tends to include more than 255 characters in the permalinks, just edit the associated line as follows:

if (strlen($_SERVER['REQUEST_URI']) > 255 ||

Replace the “255” with a larger number, like maybe 355 or something. The idea is to catch the malicious URL requests that tack on long strings of exploitative cargo.

[ Gravatar Icon ]

mrkay#39

Thanks for great security tip for WordPress. I`ll implement in my blog and write a blogpost for this tip.

[ Gravatar Icon ]

Frank#40

hello Jeff,
i had include your script in my plugin Secure WordPress - is this ok for you?
Thanks for your reply adn nice work.

[ Gravatar Icon ]

Jeff Starr#41

@Frank: Of course, we’re on the same team :) Hopefully it further help your already excellent plugin. Cheers!

Trackbacks / Pingbacks
  1. Twitter Trackbacks for Protect WordPress Against Malicious URL Requests • Perishable Press [perishablepress.com] on Topsy.com
  2. uberVU - social comments
  3. Protect WordPress Against Malicious URL Requests • Perishable Press | Rumball Motors Interactive
  4. Protect WordPress Against Malicious URL Requests • Perishable Press « Netcrema – creme de la social news via digg + delicious + stumpleupon + reddit
  5. MUST READ Wednesday 12/23/09 | Thoughts about Nothing*com
  6. delicious Links: 23. December 2009
  7. GNU GPL malware : Troj/JSRedir-AK « Documentation Mainframe
  8. Proteggere WordPress da richieste URL maligne ‹ Ubuntu block notes
  9. Hacked « wongaBlog
  10. Plugging In, Part II | DMLaBadie
  11. Descubrimientos del 23 Diciembre 2009 | Blog de unique3w
  12. 9 Vital Tips to Secure Wordpress | Security Attack
  13. 7 Easy Ways to Secure Your WordPress Site « JACKSON MURPHY
  14. 10 NEW WordPress Wanted Hacks and Powerful Techniques » DevSnippets
  15. 10 Steps to WordPress Security Protection | The Web Mechanic
  16. Lindungi URL Wordpress Dari Request Berbahaya
  17. Protect WordPress Against Malicious URL Requests | KSSP
  18. 6 Easy Ways to Secure Your WordPress Site | JACKSON MURPHY
  19. Tips Keselamatan Blog | Orange 4 Kay
  20. WordPress plugin: Protect your blog from malicious URL Requests
  21. WordPress: New Plugin Blocks Malicious URL Requests - The SEO News Blog with Pat Marcello
  22. How to Add Your Plugin to the WordPress Plugin Directory | Digging into WordPress
  23. WordPress Security Hacks
Share your thoughts..

Read Comment Policy

Comment Rules: No spam. No profanity. Use your real name. You may use simple HTML tags for style. Wrap all code in <code> tags. Learn more.



Attention: Do NOT follow this link!