Latest TweetsNew version of Disable Gutenberg includes options to disable for specific theme templates and/or post/page IDs. wordpress.org/plugins/disable-…
Perishable Press

BBQ: Protect Against Malicious URL Requests

[ BBQ: Block Bad Queries ] Block Bad Queries (BBQ) is a simple script that protects your website against malicious URL requests. BBQ checks all incoming traffic and quietly blocks bad requests containing nasty stuff like eval(, base64_, and excessively long request-strings. This is a simple yet solid solution that works great for sites where .htaccess is not available. The BBQ script is available as a plugin for WordPress or standalone script for any PHP-powered website.

Got BBQ? Get even more firewall protection. Upgrade to BBQ Pro →

BBQ WordPress Plugin

To use BBQ on any WordPress-powered site, install and activate the plugin via the WP Admin Area. Then sit back and enjoy the automatic, behind-the-scenes protection and a more secure website. No configuration required — BBQ is 100% plug-&-play. Now you can learn more about how BBQ works “under the hood”, or you can jump to BBQ Download.

Verify that it’s working

Once BBQ is installed, you can verify that it’s working by requesting the following URLs from your site (example.com):

  • http://example.com/proc/self/environ
  • http://example.com/path/?q=%2e%2e
  • http://example.com/path/base64_

These are just examples of the type of garbage that’s blocked by BBQ. If your server returns a 403 “Forbidden” response for these examples, BBQ is doing its thang. More tests are possible using the patterns contained in the BBQ firewall.

How it works

This is basically an adaptation of my G-series blacklists ported to PHP. It works by defining a set of regular expressions that match and block malicious URL requests. BBQ scans three parts of each request:

  • The Request URI
  • The Query String
  • The User Agent

Checking these variables against a strategically crafted set of known attack patterns is an effective way to protect against malicious attacks.

More information

Check the following articles for more information on the underlying functionality:

More infos on this and related topics in the security and .htaccess archives.

Download BBQ plugin for WordPress

Download the new and improved BBQ from the WP Plugin Directory:

BBQ standalone PHP script

To implement the BBQ script on non-WP sites, include the following code for each page request (e.g., at the beginning of each web page).

<?php
/*
Plugin Name: Block Bad Queries (BBQ)
Plugin URI: https://perishablepress.com/block-bad-queries/
Description: Automatically protects WordPress against malicious URL requests.
Author: Jeff Starr
Author URI: https://monzillamedia.com/
Version: (standalone)
License: GPL v2
Usage: No configuration necessary. Upload, activate and done. BBQ blocks bad queries automically to protect your site against malicious URL requests.
Tags: security, protect, firewall, php, eval, malicious, url, request, blacklist
*/

$request_uri = $_SERVER['REQUEST_URI'];
$query_string = $_SERVER['QUERY_STRING'];
$user_agent = $_SERVER['HTTP_USER_AGENT'];

// request uri
if (	//strlen($request_uri) > 255 || 
	stripos($request_uri, 'eval(') || 
	stripos($request_uri, 'CONCAT') || 
	stripos($request_uri, 'UNION+SELECT') || 
	stripos($request_uri, '(null)') || 
	stripos($request_uri, 'base64_') || 
	stripos($request_uri, '/localhost') || 
	stripos($request_uri, '/pingserver') || 
	stripos($request_uri, '/config.') || 
	stripos($request_uri, '/wwwroot') || 
	stripos($request_uri, '/makefile') || 
	stripos($request_uri, 'crossdomain.') || 
	stripos($request_uri, 'proc/self/environ') || 
	stripos($request_uri, 'etc/passwd') || 
	stripos($request_uri, '/https/') || 
	stripos($request_uri, '/http/') || 
	stripos($request_uri, '/ftp/') || 
	stripos($request_uri, '/cgi/') || 
	stripos($request_uri, '.cgi') || 
	stripos($request_uri, '.exe') || 
	stripos($request_uri, '.sql') || 
	stripos($request_uri, '.ini') || 
	stripos($request_uri, '.dll') || 
	stripos($request_uri, '.asp') || 
	stripos($request_uri, '.jsp') || 
	stripos($request_uri, '/.bash') || 
	stripos($request_uri, '/.git') || 
	stripos($request_uri, '/.svn') || 
	stripos($request_uri, '/.tar') || 
	stripos($request_uri, ' ') || 
	stripos($request_uri, '<') || 
	stripos($request_uri, '>') || 
	stripos($request_uri, '/=') || 
	stripos($request_uri, '...') || 
	stripos($request_uri, '+++') || 
	stripos($request_uri, '://') || 
	stripos($request_uri, '/&&') || 
	// query strings
	stripos($query_string, '?') || 
	stripos($query_string, ':') || 
	stripos($query_string, '[') || 
	stripos($query_string, ']') || 
	stripos($query_string, '../') || 
	stripos($query_string, '127.0.0.1') || 
	stripos($query_string, 'loopback') || 
	stripos($query_string, '%0A') || 
	stripos($query_string, '%0D') || 
	stripos($query_string, '%22') || 
	stripos($query_string, '%27') || 
	stripos($query_string, '%3C') || 
	stripos($query_string, '%3E') || 
	stripos($query_string, '%00') || 
	stripos($query_string, '%2e%2e') || 
	stripos($query_string, 'union') || 
	stripos($query_string, 'input_file') || 
	stripos($query_string, 'execute') || 
	stripos($query_string, 'mosconfig') || 
	stripos($query_string, 'environ') || 
	//stripos($query_string, 'scanner') || 
	stripos($query_string, 'path=.') || 
	stripos($query_string, 'mod=.') || 
	// user agents
	stripos($user_agent, 'binlar') || 
	stripos($user_agent, 'casper') || 
	stripos($user_agent, 'cmswor') || 
	stripos($user_agent, 'diavol') || 
	stripos($user_agent, 'dotbot') || 
	stripos($user_agent, 'finder') || 
	stripos($user_agent, 'flicky') || 
	stripos($user_agent, 'libwww') || 
	stripos($user_agent, 'nutch') || 
	stripos($user_agent, 'planet') || 
	stripos($user_agent, 'purebot') || 
	stripos($user_agent, 'pycurl') || 
	stripos($user_agent, 'skygrid') || 
	stripos($user_agent, 'sucker') || 
	stripos($user_agent, 'turnit') || 
	stripos($user_agent, 'vikspi') || 
	stripos($user_agent, 'zmeu')
) {
	@header('HTTP/1.1 403 Forbidden');
	@header('Status: 403 Forbidden');
	@header('Connection: Close');
	@exit;
} ?>

No changes need made to this code, so you should be good to go. Note that this script is somewhat different than the current version of the WP plugin. Newer versions of the plugin are optimized to work better with WordPress, but this version of BBQ continues to protect non-WP sites in general.

Note that any time you can update the BBQ blacklist in the standalone script using the latest patterns. Simply download the BBQ plugin and copy the regex array from the main plugin file.

Support

Feedback for BBQ welcome in the comments, or contact me directly.

Jeff Starr
About the Author Jeff Starr = Creative thinker. Passionate about free and open Web.
Archives
118 responses
  1. Im also having a problem with 403 errors: http://blog.sergeys.us/beer?utm_source=feedburner&amp;utm_medium=feed&amp;utm_campaign=Feed:+SergeySus+(Sergey+Sus+Photography+%C2%BB+Blog)&amp;utm_content=Google+Reader

    • Jeff Starr

      It’s the “:” in the query string that’s causing the issue.. Google should know better that “:” is a special-use character and must be encoded for literal use. It’s blocked by the plugin because it’s commonly seen (unencoded) in malicious attacks. Do you think I should remove the block and allow it?

      • Jeff,
        I do not you see the*.* in the URL?

        I cant turn on the plugin as it gets 403 on all the posts from RSS feeds. What are the negatives of removing the block?

      • Jeff Starr

        I don’t see *.* in the URL you posted, but I do see “:” (without the quotes), which is blocked by BBQ.

        I’m updating the plugin soon and think I will remove “:” from the list. Stay tuned!

  2. Hey Jeff,

    Commenting to let you know that my site also got the 403, but it’s because of Chrome that I see this happened after reading the comments. It’s a tough call to keep or remove the recent update but until this issue is resolved I sadly have to disable BBQ. I work in the Chrome browser for a reason and therefore can’t have BBQ activated.

  3. Grégoire Noyelle November 2, 2012 @ 6:06 am

    Jeff, I get an other “denied access” when I try to publish article with code inside (here is the html file. I get the problem after opy and paste this in the HTML WordPress part.

    Hope it helps.

  4. Janel Gelien November 6, 2012 @ 12:10 pm

    I can’t get Socrates 3.04 WP theme to work properly on my site if either the 5G Firewall code is included in my .htaccess file or if the BBQ plugin is installed. Any Idea which part of the code is affecting the setup of this theme? I found if I removed the word menu from the query string I could set up the menus but as far as the header and layout setup, no such luck. I would like to be able to use the plugin or firewall or both. Socrates is the only theme that seems to not work with your script but it is perfect for my new site. Any help would be appreciated.

    • Jeff Starr

      Hi Janel, what are some of the URLs that aren’t loading/working and I’ll be glad to take a look. Please wrap the URLs with <code> tags. Thanks!

      • Janel Gelien November 9, 2012 @ 11:13 am

        I’m not sure if this is what you’re asking. If for instance I go to the Socrates header setup page without the plugin activated, I can see all the options and set up the header. If I activate the plugin and bring up the same page wp-admin/admin.php?page=functions.php?option=header all I get is a blank page. Same with the layout option page and the settings page. As soon as I deactivate the BBQ plugin, they all appear and work properly.

      • Jeff Starr

        Yes, that’s what we’re after.. it looks like the plugin is blocking the URL because it contains an invalid character, the literal question mark, which should only appear once in the URL (unless encoded). Instead of using a question mark to append query strings, the ampersand “&” should be used.

        That said, it’s a tough call whether or not to remove the block for “?” from the BBQ firewall.. it protects against a lot of malicious requests. What are your thoughts?

      • Janel Gelien November 10, 2012 @ 12:20 am

        I am thinking that rather than change anything I might just go ahead and completely customize the site the way I want and then reactivate the plugin.

  5. using BBQ http://wordpress.org/extend/plugins/block-bad-queries/ in conjunction with http://wordpress.org/extend/plugins/add-from-server/ (Add From Server Plugin) seems to generate a 403. Admittedly Add From Server Plugin is outdated; I am not code-savvy enough to debug it – it is a shame because the purpose of Add From Server Plugin is to allow for adding images (that may already be in the /uploads folder…) to the WP Media Library.

    What happenned is I added about one dozen images from my server ok to test if the Add From Server Plugin would work – and it did ok :) – when I went back to add the rest my site gave me ol’ “you do not have permission….” page and it generally firewalled off ALL ? the backend – none of the css would work – the site would load but without any of its styling. Also I tried to upload an image from computer to the media library and although the image uploaded, the site would not allow access to the new image via browser.

    I deactivated and deleted Add From Server Plugin and BBQ, removed the db options for Add From Server Plugin and the site went back to “normal” and the uploaded image was once again accessible via browsing.

    One another note is I also had your 5G rules in my htaccess (while running BBQ) – I deleted the 5G rules, cleared the caches (using W3TC for that is worth informationally….) and reinstalled BBQ. Things seem to be remaining normal for the moment. I havent reinstalled Add From Server Plugin, but it sure would be useful! I have a number of images on my server that are in the in the /uploads folder that are not in the media library – would love to get them in there somehow!

    One other note is the BBQ Plugin does indeed seem to work – in spite of using the 5G rules, Bad Behavior and Akismet, I had been spending WAY too much time tweaking 404’s from bad bots and a lot of those seem to have gone away :) – I am looking forward to the next update as I am sure you must be tweaking BBQ constantly toward better functionality. Thanks

    One last note is my site is running WP 3.42 in a shared hosting environment. It is CPanel based and my host allows what are probly pretty general server permissions for a shared hosting account.

    • Jeff Starr

      I am looking forward to the next update as I am sure you must be tweaking BBQ constantly toward better functionality.

      Yes, very true :)

      Also, I’m glad to look at any specific URLs/errors that aren’t loading or working with BBQ (or 5G) installed. That’s the best way to help with the next update, just be sure to wrap each of them with <code> tags.

      Thanks for the feedback!

  6. Nathan "Spanky" Briggs November 9, 2012 @ 8:45 am

    Still having trouble with the latest and a link from twitter, because the URL includes %27.
    I’ve edited BBQ on my client’s sites to remove the %27 match from. Could you include removing %27 from the match list for the next update?

    Hugs,
    Nathan

  7. MickeyRoush November 12, 2012 @ 1:15 am

    You should really reconsider your blockage of %27. True it’s the root of all evil XSS attacks but those usually use more than one of those. Blocking that may also block users searching for something with it being once in the string. You should right a bypass for if there is only one occurrence of %27 and that more than one will trigger the block. I’ve created my own Block Bad Queries based from _ck_’s original plugin and I’ve been able to do so.

    It also seems that you may have to whitelist the admin for certain things again. In my opinion, if an attacker already has admin privileges, there’s so much damage they can do that most plugins can’t really help against anyways.

  8. Hello,

    I am having a problem where I started losing traffic from Facebook after installing this plugin. I had to disable it!

    The URL FB was passing it as follows:

    http://website.com/something.html?fb_action_ids=470231656363161&amp;fb_action_types=og.likes&amp;fb_source=other_multiline&amp;action_object_map=%7B%22470231656363161%22%3A289507891167454%7D&amp;action_type_map=%7B%22470231656363161%22%3A%22og.likes%22%7D&amp;action_ref_map=%5B%5D

    Could you please fix the plugin so at least FB traffic is not blocked.

    Thank you.

    • Jeff Starr

      Thanks for the feedback, Adam – we’re currently updating the plugin and will try to get this fixed up for the next version. The URL example is a huge help – Thanks for posting.

  9. I took a minor liberty with BBQ and implemented the following in lieu of 403, beginning Line 28 ;-)

    header('HTTP/1.1 418 I'm a teapot');
    header('HTTP/1.1 418 I'm a teapot');

  10. kewl :)

    My syntax seems to be off a little above; btn the curly brackets, try:

    header('HTCPCP/1.1 418 I'm a teapot');
    status('HTCPCP/1.1 418 I'm a teapot');
    header('Connection: Close');
    exit;

    Disappointingly, my host does not seem to support 418, I keep just getting the boring ol’ 403.

  11. Hi Jeff,

    I am using a plugin called WP No External Links which masks my outgoing links. It changes the link from lets say http://www.google.com to j32design.com/goto/http://www.google.com and uses 302 redirect.

    I use this plugin and the BBQ plugin since quite a long time now, but as far as I could see in google webmaster tools I started to get 403 Permission Denied errors for all my outgoing links somewhere in the end of October.. The redirects work fine as soon as I turn the BBQ plugin off. Now, I really don’t want to turn it off.

    Is there anything you or I can do to make them both work together?

    Thank you in advance for your time.

    • Jeff Starr

      The reason the URLs are blocked in this case is because they include http:// unencoded in the request string. Unfortunately that particular string is common among malicious requests, so is blocked in the BBQ plugin. The question now is do we remove protection for requests containing unencoded http://? What are your thoughts?

  12. Thank you Jeff for getting back to me. For now I decided to turn of the plugin that masks my outgoing links until I find a better solution. The masking plugin has an option where it replaces the url with a random number, which seems to work, but I have to see how it will effect my blog regarding speed.

[ Comments are closed for this post ]