Shedding unwanted requests at the server layer

For as long as websites exist, the robots, bad guys, and wannabe internet supervillains will spam our servers with junk requests in hopes of finding known attack vectors.

Due to a variety of circumstances – including, but not limited to, poor decision making, technical debt and aggressive backward compatibility policies (please, just leave the old, bad/deprecated API behind) – server software of all flavors will inevitably leave itself vulnerable in some spots.

Looking through my server logs, I can see these dubious dunces trying to ping files that would tell them about a widely- and publicly-known soft spot on my server that they can further dig their grubby little fingers into.

Let’s walk through a quick example in xmlrpc.php, brought to us by Wordpress.

xmlrpc.php

I’m not actively hosting any PHP apps at all, so a request for anything.php appearing in my server logs is an obvious bad actor. In this particular case, this file is a known attack vector in the world of Wordpress.

If our most-definitely icky-breathed fellow human gets a positive hit from my server when trying to request this file, there are at least a few implications:

  • they will know the site they tried to hit is a Wordpress (WP) site, and could potentially log this note in a database somewhere for further abuse in the future (there are many other ways to identify WP sites, so this isn’t necessarily a big deal on its own, but it’s not nothing)
  • XML-RPC is present, and this known attack vector is just sitting here, pants down, susceptible to brute force attacks, among others
  • they also now know that your server runs some sort of LAMP setup (to run the actual WP software), and, while most of the software installed there is typically quite tanky, this gives more clues as to what additional items are on the menu for a bad actor to try to take advantage of (e.g. one could try to brute force SSH access to your server, poke around to take advantage of lazy/bad system administration, try to get in via FTP… this could be its own post)

So this seems to be a pretty juicy vulnerability, and, frankly, it’s a bit wild that it’s turned on by default. This isn’t super relevant for me, as I’m not running a WP site. I would, however, like to keep the riffraff from laying their diddly hands upon my precious applications.

let’s turn them away at the gate

Until I do something to protect myself, when one of these party-pooping good guy haters want to try to poke at (read: make a request to) my frontend for xmlrpc.php or any other file that may tell them about soft spots, my firewall, not knowing any better, passes the request along to the server layer, which also doesn’t know any better and passes it on to the application layer. Fortunately, Sveltekit has no idea what to do with PHP, and it’s dead in the water there.

I’m not OK with my babies having to deal with the stranger danger in the first place, though. I want to send them away at the outer layer of the onion; as early in the request as possible, I want to check a list known attack vectors, and send ‘em packin’.

Better yet, since I’m not currently using any PHP at all, I can just keep an eye out for all requests for .php files, and send ‘em packing right then and there.

The server layer is a good place to do this. We could do this at the application, but why even bother running the extra code? Why even hand the request off to the application at all, if I can do the job with Nginx? At any sort of scale, doing so could add up to a pretty beefy savings in bandwidth and work that your server has to do.

An easy way to configure Nginx to turn away all PHP requests is to add a couple of simple lines to our Nginx config. On Linux machines, this is usually somewhere in /etc/nginx. We need to add a location block within our server block.

server {
    # ... boring SSL stuff and whatnot

    # a simple regex to match all PHP files, and deny access
    location ~ .php {
        deny all;
    }

    location / {
    	# ... the real application 
    }
}

And that’ll do it! Restart your Nginx process (sudo systemtctl restart nginx or sudo service nginx restart should do the trick if you’re on Debian), then try sending some request to your site for anything.php and verify that it’s getting turned away. Your Nginx instance is now basically digital Marshawn Lynch, leaving a trail of dejected, unwanted .php requests in its wake.

This is just a regular expression (regex), so if you wanted to modify this to only block specific files, you can tweak this regex and make it as complex as it needs to be to match your use case, or introduce additional location blocks.

©2024 Joe Castelli