-
-
Save jaydansand/dcb66a0e36365c178a91 to your computer and use it in GitHub Desktop.
<?php | |
/* | |
Plugin Name: XMLRPC Slowdown | |
Plugin URI: | |
Description: Deliberately introduce some delay into XMLRPC calls to rate limit brute-force and DoS attacks. | |
Version: 1.0 | |
Author: Jay Dansand, Technology Services, Lawrence University | |
Author URI: https://gist.github.com/jaydansand | |
*/ | |
/* Copyright 2014 Lawrence University | |
This program is free software; you can redistribute it and/or modify | |
it under the terms of the GNU General Public License, version 2, as | |
published by the Free Software Foundation. | |
This program is distributed in the hope that it will be useful, | |
but WITHOUT ANY WARRANTY; without even the implied warranty of | |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
GNU General Public License for more details. | |
You should have received a copy of the GNU General Public License | |
along with this program; if not, write to the Free Software | |
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | |
*/ | |
/** | |
* Implement filters xmlrpc_enabled and xmlrpc_login_error. | |
* | |
* @see class-wp-xmlrpc-server.php | |
*/ | |
function xmlrpc_slowdown_filter_sleep($arg) { | |
// Keep track of calls (should be 1 or 2) to increase delay | |
// when called after a login failure. | |
static $calls = 0; | |
++$calls; | |
$rand = function_exists('mt_rand') ? 'mt_rand' : 'rand'; | |
usleep(call_user_func($rand, 500000 * $calls, 2000000 * $calls)); | |
return $arg; | |
} | |
add_filter('xmlrpc_enabled', 'xmlrpc_slowdown_filter_sleep'); | |
add_filter('xmlrpc_login_error', 'xmlrpc_slowdown_filter_sleep'); |
Thanks for the comment/concern! I get the theory, but I must be missing something: if each attacking node (for example, let's say 50 of them) limits itself to any finite number of simultaneous connections (let's say 5), then regardless of whether you're responding really quickly or really slowly, they're still going to be occupying on average 50 * 5 = 250 workers (or any other finite number) at a time, right? The only situation where this script would cause a logjam (where there wasn't nearly one already) is where the brute force attacker is simply spawning new requests as quickly as it can, not waiting for previous requests to finish. That's no longer someone trying to log in, that's someone trying to take you down. Admittedly, this script does not help with that at all!
FYI, I've seen this kind of mitigation in use before and if someone is bruteforcing xmlrpc, the results aren't pretty - you'll end up with all your workers occupied because each call is taking a lot longer. I'd simply no-op an increasing percentage of requests so the workers can finish a request and move onto the next etc.