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!
Focused on clean code and quality content, Perishable Press is the online home of Jeff Starr, author, artist, designer, developer, and all-around swell guy. 





64 Responses
Add a comment
Alex Denning – #1
Great tip Jeff. Thanks for that. Going into my framework :)
Eric B. – #2
Very useful security tip. Thanks for sharing!
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.
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
Aldo – #5
Merry Christmas, Jeff, and thanks again for your precious posts. :-)
Lillan – #6
Useful indeed! Tnx :)
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
GETparameters invalid.@Rick Beckman: If you call this code before WordPress has fixed the broken
REQUEST_URIon IIS it won’t work there.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.
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?
JP – #10
Is this something everyone should implement, or are only pre-WP 2.9 blogs vulnerable?
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.
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 */}Yael K. Miller – #13
I’m a little confused with that to do with this. Is the below correct?
blockbadqueries.phpwp-content/pluginsJeff 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.
Greg – #15
@Jeff Starr Hi Jeff, as you said yourself:
“
a{n,}specifiesnor more of the preceding character. e.g.,x{3,}matches three or morex’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. :)
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
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.
John Hoff - WP Blog Host – #18
Jeff, could this code be altered to include such strings as
CONCATandUNION+SELECT?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!
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;} ?>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?
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!
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.
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.
Aldo – #25
Hi Jeff, right! :-)
Thanks!
This plugin should go in the wordpress repository.
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 ?
Jeff Starr – #27
Yael, go with the plugin given in comment #24. I need to update the post with the improved code.
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.
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.
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.
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!
elcidi – #32
This is very much helpful to increase the security.
Many thanks foe sharing it
Jauhari – #33
I will install on my Blog ;)
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.
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.phpfile, just for kicks).ikram – #36
thanks. very usefull
I will use it on my blog
regards
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.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 maybe355or something. The idea is to catch the malicious URL requests that tack on long strings of exploitative cargo.mrkay – #39
Thanks for great security tip for WordPress. I`ll implement in my blog and write a blogpost for this tip.
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.
Jeff Starr – #41
@Frank: Of course, we’re on the same team :) Hopefully it further help your already excellent plugin. Cheers!
Trackbacks / Pingbacks