Securing Drupal 7

31 August 2011
As Drupal 7 becomes more popular it will also become a larger target for attackers. It is important to take steps to keep your Drupal 7 installation secure. The following are a set of guidelines that can be used to ensure the stability and security of your Drupal 7 installation. Some of the suggestions might be considered a little paranoid, but it's always better to be safe than sorry, and layers of defense will help defeat determined attackers.

The arrival of Drupal 7 has generated a lot of excitement. At the time of this writing the latest version of Drupal, Drupal 7.0, is still extremely new. Many of the most common supporting modules are still in pre-release versions (alpha, beta, and release candidate (rc)). Drupal 7 includes a number of significant improvements that will make it attractive to folks looking to deploy a CMS solution.

As Drupal 7 becomes more popular it will also become a larger target for attackers. It is important to take steps to keep your Drupal 7 installation secure. The following are a set of guidelines that can be used to ensure the stability and security of your Drupal 7 installation. Some of the suggestions might be considered a little paranoid, but it's always better to be safe than sorry, and layers of defense will help defeat determined attackers. Some of the suggestions may come at the expense of usability, but in many cases this is an acceptable trade off.

1. Remove the PHP filter module.

Drupal 7 comes with the same PHP input filter that previous versions have come with. This is an extremely dangerous feature that is hardly ever necessary. PHP can be used in nodes or for determining visibility of elements like blocks or views. In each of these cases the PHP can be moved to a theme template file, which is more appropriate (as themes govern display logic), is easier to maintain (it's easier to find PHP code in themes and easier to spot custom templates than it is to check obscure text fields in the admin interface), and it moves PHP out of the database and into the filesystem where you can enforce filesystem security protections. If an attacker ever gains the ability to write PHP via a web interface on your server the jig is up - the attacker can easily take full control of the server.

Removing PHP is a two step process. First ensure that the module is disabled and no associated permissions are being used for PHP. Next, delete the entire directory for the module, found under drupal-7.0/modules/php if you do a default installation. The module code can safely be removed without causing any harm to the Drupal installation.

To prevent other modules from re-introducing PHP you can hide any permission that grants PHP access using the following patch for Drupal 7.0. This patch hides the permissions from the administrative interface so they can't be granted unless you have direct access to the database.

 --- modules/user/user.admin.inc	2011-05-03 08:50:31.816720943 -0400
 +++ modules/user/user.admin.inc	2011-05-03 08:50:03.062614491 -0400
 @@ -695,6 +695,7 @@ function user_admin_permissions($form, $
            'restrict access' => FALSE,
            'warning' => !empty($perm_item['restrict access']) ? t('Warning: Give to trusted roles only; this permission has security implications.') : '',
          );
 +        if (stripos($perm, 'use php') === FALSE) {
          $options[$perm] = '';
          $form['permission'][$perm] = array(
            '#type' => 'item',
 @@ -707,6 +708,7 @@ function user_admin_permissions($form, $
              $status[$rid][] = $perm;
            }
          }
 +        }
        }
      }
    }
 

To install the patch log into your Drupal server and navigate to the Drupal installation directory, for instance, /var/www/html/drupal-7.0. Next copy the patch into a file called user.module.patch. Next test the patch the file using:

 $ patch -p0 --dry-run < user.module.patch
 
 

If you don't see any errors you can patch the file (and create a backup of the original) using:

 $ patch -p0 -b < user.module.patch
 
 

This will safely hide PHP permissions so they can't be enabled later on.

2. Remove unnecessary files and block access to others.

There are four main files - authorize.php, upgrade.php, cron.php and install.php that are used to perform administrative functions on your Drupal site. There's no reason for random internet users to be able to see these files. Go ahead and restrict access to them using the Drupal .htaccess file. By adding the following lines to your .htaccess file you restrict access to connections from localhost (in much the same way that Webmin or Swat limits access).

 <FilesMatch "(authorize|cron|install|upgrade).php">
   Order deny,allow
   deny from all
   Allow from 127.0.0.1
 </FilesMatch>
 

Next delete all the .txt files in the root of the Drupal installation. This includes README.txt, CHANGELOG.txt, INSTALL.txt, etc. Be sure NOT to delete the robots.txt as that file is needed by web crawlers. Delete the web.config file if you don't need it. You can also safely delete the xmlrpc.php file unless you know you're going to need it. Most sites don't use XML remote procedure calls so more than likely this file is just cruft.

3. Change the UID 1 account.

The first account you create for your Drupal 7 system is the UID 1, or superuser, account. This account has all privileges and cannot be denied any privilege. It is an extremely powerful, and dangerous, account. Try to create this account as an administrative account, can create a separate user account for your own use. Try to get in the habit of using your user account and only relying on the UID 1 account when you have to. Be sure to choose a good, strong password for the UID 1 account.

4. Logging.

Drupal 7 logs to a table called Watchdog, and keeps logs for a certain amount of time based on settings and cron runs. Be sure to enable the core 'Database logging' module (which is enabled by default. This stores log records in the database. Additionally, enabling the Syslog module allows Drupal to write logs to standard syslog facilities. This is extremely helpful because it allows you to integrate Drupal into your existing log management and monitoring solutions. It also moves Drupal's logs out of the database, so that if your site was compromised an attacker wouldn't be able to delete the logs simply by manipulating the database. You should also adjust the logging capacity, so that errors are not displayed to the screen, once your site is in production.

5. Brute force protection.

Automated password guessing attacks are a feature of the internet these days. You should take steps to protect your site against these forms of attacks. Consider installing and using a module like reCAPTCHA (http://drupal.org/project/recaptcha) and putting a CAPTCHA on the login form, or Flood Control (http://drupal.org/project/flood_control) to cut down on the number of abusive login attempts. Using a module like Real Name (http://drupal.org/project/realname) will also allow you to somewhat disguise the account names of users if you limit permissions to "View user profiles" at admin/people/permissions.

6. Permissions control.

Be wary of any permission listed at http://drupal.org/security-advisory-policy (administer filters, administer users, administer permissions, administer content types, administer site configuration, and administer views). As previously stated, disabling PHP will obviate some of these but some permissions, such as 'administer site configuration' are used by non-obvious modules and can be leveraged to compromise a Drupal site quite easily. Guard those permissions jealously. It's worth considering creating a third group between "Authenticated user" and "Administrator" and limiting these permissions to just "Administrator" roles.

7. Accepting modules absent security support.

Be aware that the Drupal security group doesn't support any modules in pre-release (http://drupal.org/node/475848). This is particularly important in the early life of Drupal 7 when most modules are in pre-release. It's important to understand the risk of not having security support for these releases.

Never, ever, ever, install a "dev" module on a production site, no matter what the people in support forums say. Not only are "dev" modules unsupported by the Drupal security team, but also they are unstable, may have functional flaws, and could do all sorts of bad stuff to your site. It's an unfortunate trend that many support responses include "install the latest dev branch." This is bad advice, don't follow it!

8. Final administration touches.

Once a site is developed and deployed consider disabling and removing the Views UI module (part of Views). This removes the ability to adjust, edit, or create Views, but it also ensures that no one can maliciously, or even accidentally, alter your Views. This offers a big stability as well as security advantage.

9. Database security

Your Drupal installation will require a database for persistence and data storage. Be sure to protect your database and database server with the same care as you protect your Drupal front end. Be sure that remote connections to the database server are restricted (port 3306 for MySQL should not be available to the outside world).

Dedicate a database to Drupal. This helps to segregate your data so it's more portable, easier to maintain, and more reliable (there's no chance of another application overwriting key data).

Ensure that you utilize a secured account dedicated to the Drupal instance, with only the necessary permissions to operate the Drupal site (no permissions to write files to the filesystem). DO NOT USE THE MYSQL ROOT ACCOUNT FOR YOUR DRUPAL INSTANCE!

Be sure that you perform regular database backups. This can be as simple as using the mysqldump command to back up the database on a regular basis. If you perform backups you must be sure to test your restore procedure to make sure your backups are useful!

10. Filesystem security

Make sure you follow good filesystem security practices. Don't allow the web server to write to any files or directories that aren't necessary. Make sure you restrict access to the settings.php file, which contains database credentials in clear text. Make sure attackers can't create new files or manipulate files if they manage to gain access to a system account (such as through a brute force SSH attack).

As with databases, be sure to back up the filesystem files. Test your backup and restore procedure to ensure your backups will be useful if you ever run into a problem.

11. Remove unnecessary services

This old maxim from Linux and Unix hardening guidelines is no less true with Drupal. Look at the modules in your module listing. There a number of modules in Drupal core that you may never use. You can safely delete these directories from the root modules directory. If you decide you ever want to use them you can always download a new copy of Drupal core and copy them back in. Many core modules are rarely utilized, and sometimes contain security problems. Removing these modules is an easy way to ensure the stability of your site (they won't get accidentally enabled) and it provides great defense against threats to those modules. You can extend this principle to contributed modules as well (for instance, if you're using the CTools module, but not the 'Chaos Tools (CToools) Ajax Example' then delete or remove the directory /sites/all/modules/ctools/ctools_ajax_sample from your Drupal root.

12. Limit upload types

Unfortunately Drupal 7 doesn't have one central place to define file upload types that are allowed on your site. Instead, each content type file field can have it's own types defined. You want to be particularly leery of binary formats (.exe, .vbs, etc.) but also be careful about formats that could have embedded binaries (office documents with Flash embedded in them for instance). Be especially careful of files that could be rendered by the web server (such as .php, .phtml, .php3 or even .html files).

13. Spam

Unfortunately as soon as you set up your Drupal site spammers will begin to target it. Be very leery of allowing anonymous users to create accounts without e-mail confirmation. This sets a low bar to bot created accounts, but it's something. At the other end of the extreme consider forcing users to create accounts with e-mail confirmation. To keep spammy comments and contributions down consider using a CAPTCHA. Another simple way to lower the number of spam comments is require users to have accounts to create comments. This may retard the activity of comments, however. At the very least make sure anonymous comments are moderated in an approval queue (be sure the 'Anonymous user' group does not have the 'Skip comment approval' permission.

Be sure anonymous users can't create, or edit nodes of any type. Some spam bots, or malicious users, will seek to edit existing content in order to add bad content. This is sometimes overlooked, but 'edit' permissions can be just as dangerous as 'create' permissions.

14. Keep Current

Use the Drupal core 'Update' module. Enable it and have it send you e-mails when new versions of modules (or Drupal core) are available. Install updates when recommended as soon as possible. Many updates are issued to address security vulnerabilities, and once the update (and vulnerability) become public, your site could become a target.