Secure Drupal files with fsniper

Case type:

Service area: 

Technologies:

Keeping file system with secure permissions has been always a critical task when it comes to administer a webserver. Not every time files uploaded via the webserver are saved with the correct permissions. Running a cron job to fix them could be a solution but how to deal with the case when an attacker can very quick exploit files wrong set permissions?

A simple solution would be using fsniper to set the file permissions in real time, in the moment when a file is uploaded or changed on the file system. As I used this on several Drupal sites, this writeup is based on a Drupal 7 installation.

Download

Download fsniper.config.tar.gz!

This is the config file used as example or start point.

What is fsniper?

fsniper is utility that adds one or more watchers to certain directories and calls specific scripts to act when a watched file is modified. fsniper uses inotify to watch for when a file is closed after being written to. This means that utilities such as touch will cause the event to trigger.

fsniper can watch any number of directories for any number of pattern matches on the files.

Home of fsniper: https://github.com/l3ib/fsniper.

Limitations

Unfortunately we cannot act also on directories. We know that, at least in Drupal, the webserver is also creating directories under file system (e.g. sites/default/files/css).

Also the the watched directories selectors are lacking of Regexp support. This makes things a little bit difficult when it comes to fine tune watchers on some directories. But in most of the cases fsniper fits your needs.

Install

Download from https://github.com/l3ib/fsniper. See install notes in README. On Ubuntu install __fsniper__with:

$ sudo apt-get install fsniper

Configure

This section explains the generic configuration of fsniper but you can check later a typical Drupal case.

fsniper will run under root user and it uses a configuration file that defines what directories to watch and what scripts to run.

Login as root and go in the home directory:

$ su -
$ cd

Create the directories for fsniper:

$ mkdir /root/.config/fsniper/scripts

Create the fsniper config at /root/.config/fsniper/config. Add the configuration following the next syntax. You should read also the documentation on the Github site:

watch {
 
  # Adds a watcher to the Drupal files directory. Note that
  # we are using "myuser" as example of the user set as owner
  # of the Drupal codebase (typically the user under you’ve
  # installed Drupal. "www-data" is the user under the webserver
  # runs.
  /var/www/html/sites/default/files {
    recurse = true
 
    # The files/.htaccess needs a special treatment.
    /^\.htaccess$/ {
      handler = fix_drupal myuser www-data u=rw,g=r,o=
    }
 
    # Recommended permissions for Drupal files.
    * {
      handler = fix_drupal www-data myuser ug=rw,o=
    }
  }
 
  # Add here other custom rules for custom cases.
  # ...
}

You saw that the handler previously set is a script called fix_drupal. The script has been called with some parameters. It’s easily to guess that they are referring to owner, group, and chmod flags.

It’s really easy to understand this config file. First, the watch {…} wrapper is mandatory. Inside we can watch one or more directories. In this case we are watching only the Drupal files directory and that is /var/www/html/sites/default/files. Here we cannot use Regexp to select watched directories. The recurse = true clause tells fsniper to descent into sub-directories.

Then you have to add a list of rules. The first rule applies to .htaccess file. This file should be not writable by the webserver when the site runs. There are cases when a new version of Drupal may want to update that file You should treat such cases. The second rule refers to all other files. You can use wildcards here too as well as Regexps.

Now let’s take a look at the script file. This you’ll need to place under /root/.config/fsniper/scripts. In our case the script has the full path /root/.config/fsniper/scripts/fix_drupal and the following content:

#!/bin/bash
 
chown $1:$2 $4
chmod $3 $4

Don’t forget to make this script file executable.

fsniper can be ran as daemon or you can create a start/stop script in /etc/init.d/fsniper and run this script when the machine boots. We’ll see this later in the Drupal example.

A typical Drupal example

Download the fsniper.config.tar.gz archive that contains ready made .config directory and a README.txt file. Here are some steps to use this example:

Login as superuser:

$ sudo su -
$ cd

Download and unpack the archive:

$ wget http://webikon.com/files/attachments/fsniper.config.tar.gz
$ tar xzvf fsniper.config.tar.gz

Move the .config directory under /root:

$ mv /root/fsniper/.config /root/

Adapt you configuration. Be careful at your watched directories and name of users. Make your scripts executable:

$ chmod +x /root/.config/fsniper/scripts/*

Create a /etc/init.d/ service by simply symlinking the provided script:

$ ln -s /root/.config/fsniper/scripts/fsniper /etc/init.d/

Make fsniper start at machine boot. I’m illustrating with a Debian/Ubuntu command:

$ sudo update-rc.d fsniper defaults

You’re done! Now you can test what’s going on:

Create a new empty file in Drupal files:

$ touch /var/www/html/sites/default/files/some_new_file.txt

Check the ownership and permissions. Normally the file is created with root:root as owner but you’ll see that fsniper already fixed the owner to www-data:myuser and permissions to -rw-r-----.

Troubleshooting

Check the /root/.config/fsniper/log file to track all fsniper actions and/or failures.

Disclaimer

I provide no warranty for any damage caused by the correct or incorrect usage of this writeup. You can use everything from this article on your own risk.

Resources