Drupal is an open-source content management system with a quite complex architecture. It also has a strong security model. Thanks to the big community of developers there is a lot of informative documentation and useful examples of the proper configuration of Drupal website security and keeping this configuration up-to-date.
It should be kept in mind that Drupal is the only one part of the software which is needed to run a website. To protect the whole system from hacking, we need to take care of an entire set of software. It includes some common server settings, the configuration of a web server, PHP and a database. Also, the proper configuration is required for any additional software on a server.
This article focuses on discussing the mentioned key points. It provides some clues which should help the server and website administrators to audit the security of the entire system. We should understand that it’s impossible to create a system which is absolutely safe but if you stick to some common principles, it will help to support an indicator of the safety of your system at the sufficient level.
We will consider the following aspects of the website security:
Let’s start with the common security rules. Most of them are applicable not only to the Drupal development and supporting the security of the relevant for the Drupal website functioning infrastructure but also in many other cases:
- Use widespread solutions that are developed by a large community of users. It can be well maintained open-source libraries, popular Linux distributions and so forth. Always check the integrity of the downloaded code.
- Limit usage of any additional software. Install new software if you really need it and there is no ability to use the similar functionality from already installed packages. Uninstall all the software that you don’t need.
- Avoid writing a custom code. Before you start doing it, think carefully whether you can avoid this. A real situation related to the Drupal development is the search for ready solutions on drupal.org before writing custom modules.
- Deny an access by default. You should grant an access to objects in your system only when it’s necessary.
- Add roles with required permissions. Each role must be well documented. In that way, it should be easy to support and extend a whole roles/permissions system.
- Do not use superuser privileges. On Linux-based operating systems only use the root access when required and do this through sudo. In other words, you shouldn’t be logged in as root.
- Document everything. First of all, it’s about any customizations of your system. It’s quite easy to forget some important details and they can be lost during the system update.
- Do periodic security checks of your system. You should carefully analyze all suspicious cases and react to them.
- Take care of backups. You must always have an ability to revert the system back to any of previous states. Besides, you need to be sure that the system makes the workable backups.
- Do not open the access to your server from the Internet before the server is properly protected.
These principles can be applied to any system, regardless of a set of software and hardware that it uses. However, there are more specific key points what we will discuss further.
In addition to Drupal to run a website, it’s necessary to configure PHP, a web server, and a database server. You may also want to install some software for extending search functionality, for working with cache and so on.
As you see there is a lot of things that require the proper configuration and regular maintenance. Based on said above, we can distinguish the following objects for which we need to ensure security to some extent:
- Server (common settings)
- Web server
Security of any service available on the Internet begins with a basic configuration of a server. For the Linux-based servers it can include the following steps:
- Change the login process to the server
- Setup a firewall by using iptables
Change the login process to the server
By changing the process of logging in to the server, I mean a certain modification of the default server settings. The main goal is to make this process different from the standard one.
For example, any Linux-based system has a superuser that is called root. An attacker can try to pick up a password for this user. However, if a server administrator turns off root logins, such attempts will be unsuccessful. Instead of the root user, we could create a new one and then grant him the necessary permissions.
Most of the discussed changes are related to ssh settings. They are usually located in the /etc/ssh/sshd_config file. Take a look at this configuration:
Port 2345 Protocol 2 PermitRootLogin no PasswordAuthentication no UseDNS no AllowUsers user
It allows a user with a name user connect via ssh to the server by using 2345-port (not standard). It also disables root logins and a password authentication.
Disabling the password authentication is an important step to improve the security of the whole system. The passwordless authentication is more secure. To log in to the server you need to generate an ssh key-pair on a local machine and then copy a public key to the server.
Setup a firewall by using iptables
The iptables utility is the default firewall for Linux systems. It can be used for managing connections to the ports that you specify. If we want to keep the website on the server, in addition to the ssh port it will be necessary to open http and/or https ports.
By default, there are no rules on a clean operating system. Typing the sudo iptables -L command (Ubuntu) returns the following entries:
Chain INPUT (policy ACCEPT) target prot opt source destination Chain FORWARD (policy ACCEPT) target prot opt source destination Chain OUTPUT (policy ACCEPT) target prot opt source destination
This means that the server accepts anything from anyone on any port (policy ACCEPT). Let’s try to open the necessary ports and refuse connections to other ports for an input chain.
sudo iptables -A INPUT -p tcp --dport 2345 -j ACCEPT sudo iptables -A INPUT -p tcp --dport 80 -j ACCEPT sudo iptables -A INPUT -p tcp --dport 443 -j ACCEPT
These commands accept connections to 2345-, 80- and 443-ports. Despite this, we still have no other restrictions for other ports. So, you need to add a rule to an end of the input chain that will refuse all inappropriate packets.
sudo iptables -A INPUT -j DROP
That’s all. It should be borne in mind that the settings above may vary greatly depending on a chosen operating system. The main goal here is only an explanation of the basic principles. Be careful when changing network settings. Sometimes it can make a remote server not available for any connections.
A few general guidelines for setting up a web server. Applying these rules is very important for the functioning of your website. By using server vulnerabilities attackers can manipulate website files, upload malicious scripts and run these scripts somehow.
Access to the website files
There is the main rule - the website files should be editable by a non-root user and shouldn’t be writable by a web server user. The Drupal files/ directory in some cases can be available for writing by the web server’s user. The detailed information on securing file permissions and ownership can be found in the Useful links block at the end of the article.
Restrict an access to some pages on the web server level
Sometimes it may be useful to restrict an access to several pages of the website on the web server level. For example, in a situation when you have a demo website or a website without a registration functionality. So, you can protect the /user and /admin/* routes. For the Apache web server, it can be done by using the mod_authz_host and mod_rewrite modules. Keep in mind that using a http authentication isn’t a secure approach. Thus, the described method is more applicable in a given case.
Remove the unused web server extensions
All additional software on the server is a potential security risk. So, you should minimize a set of necessary tools. If you don’t need something, just remove it.
The same is applicable to the web server. Apache and Nginx web servers have a lot of additional extensions which can be used for some purposes. Carefully check a list of enabled extensions and remove all not used extensions.
Usage of the HTTPS protocol makes the website and an access to the private users’ data more secure. Nowadays it’s an absolutely impossible situation when some online stores don’t use encryption for their payment transactions. Moreover, Google sets HTTPS as a ranking indicator. It means the websites which don’t use the HTTPS protocol but at the same time process, some important information (credit cards details, payment transactions, etc.) get a negative impact on search rankings.
An ideal case is if you apply encryption for all websites that have an interaction with users. An obvious example of such an interaction can be the login and registration forms. Users type their passwords to these forms. Even if these passwords look invisible (like black circles in a field) in all browsers, they are passed through a network in an unencrypted form. So, if attackers have an access to the network, they can easily intercept the data entered. Quite often users have the same passwords for different services. This means that access to other services can also be compromised.
It should be clear in what situations you can use an HTTP authentication. Most often you need it to protect an access to a staging website and disable indexing of this website by search bots. However, the HTTP authentication is inherently insecure. It doesn’t use any encryption algorithm. So, the traffic between your browser and the website isn’t encrypted and an attacker can get the access to the website just by copying the “Authorization” HTTP header and sending it the web server.
Also, it’s strongly recommended to keep the htpasswd file outside of a document root. Set read-only permissions for this file (440).
PHP like other parts of the server infrastructure can contain vulnerabilities. Here much depends on the settings of PHP itself and on what version of PHP is currently used. Of course, you always need to check all available updates and keep PHP updated. However, in some situations, it can be quite difficult or even impossible.
In general, all the work to optimize the safety of the operation of PHP on a server can be divided into three parts:
- Periodic update of PHP version
- Avoiding the use of an insecure code, functions, etc.
- Optimizing PHP settings
Periodic update of PHP version
It’s an obvious thing but, as I mentioned, in some cases updating can be quite difficult or even impossible. It can happen in a situation when you have a lot of legacy code in your application (it doesn’t work in the new PHP version) and the current business strategy doesn’t allow you to spend time on updating this code because it’s time-consuming operation. In such a case, you can try to apply some recommendations which are described below.
Avoiding the use of an insecure code
Writing a secure code is an important step in the whole application security. You should spend some time on a regular basis for reviewing all the custom code that you have. Besides, no one can give a guarantee that the third-party libraries do not contain any vulnerabilities. As I mentioned, even PHP itself can have problems with security (using insecure functions, buffer overflows, etc.).
To solve these problems there is a good solution called Suhosin which can help you to get rid of many security issues. Suhosin was designed to protect servers and users from known and unknown flaws in PHP applications and the PHP core. It consists of two parts. The first part is a patch for the PHP core which provides a few low-level protections against buffer overflows or format string vulnerabilities. The second part is a PHP extension that implements some additional protections.
Suhosin is a really powerful tool for protecting your server against a lot of vulnerabilities. Unfortunately, it isn’t available for PHP 7. In fact, the work on Suhosin7 is being carried out, but it isn’t finished yet. The author doesn’t recommend using Suhosin7 on production servers.
Optimizing PHP settings
The two easiest steps that we can take in order to optimize the PHP security configuration are disabling unused modules and minimizing an amount of information that users can get about a current PHP installation.
To see all of the compiled PHP modules, run the following command:
$ php -m
It’s recommended to use only the most necessary modules to increase security. Carefully check the entire list and decide what modules you don’t need.
Protection of PHP from hacking is not only an accurate programming but also hiding information about a system. Take a look at this string in the php.ini file:
expose_php = Off
Make sure that this parameter is turned off. Otherwise, PHP will send the installed version in response to all requests in the X-Powered-By header.
The same thing applies to the PHP errors on a website. They can provide some additional info about your server (a type of the web server and its version, the structure of directories, etc.). So, it’s highly recommended to disable this feature on production servers.
display_errors = Off log_errors = On error_log = /var/log/httpd/php_scripts_error.log
The settings above allow you to turn off displaying errors occurring all around the website. Also, they activate logging of errors into the specified file.
Those were preliminary steps that will help you increase the security of using PHP on your server even without any significant modification of the system. Now let’s talk about some specific restrictions that you can add to the PHP configuration (php.ini file):
- Disable file uploads
file_uploads = Off
But if such a function is necessary, it’s better to limit a file size.
file_uploads = On
upload_max_filesize = 1M
- Control system resources
max_execution_time = 30
max_input_time = 30
memory_limit = 50M
You can specify the maximum execution time for each script, the maximum amount of memory and the maximum data read time.
- Disable PHP functions which allow scripts to refer to other URLs
allow_url_include = Off
allow_url_fopen = Off
If allow_url_fopen is enabled, PHP can use file functions such as file_get_contents. With it, the script can download files from remote servers.
- Disable dangerous functions
Before disabling, make sure that your website doesn’t require any of them.
- Restrict an access to the file system
open_basedir = "/var/www"
The open_basedir directive allows you to set a directory in which PHP can access files using functions such as fopen, file_get_contents, etc. If the file is outside of this directory, PHP will refuse to open it.
- Check the session path
session.save_path = "/tmp"
Make sure that the session path is outside the website root directory. Also, it mustn’t be readable or writable by other system users.
What measures you will take to ensure a database security depends primarily on the infrastructure of your application. For example, a Drupal’s database abstraction layer gives you an ability for choosing between different databases. Out of the box, it can be MySQL, SQLite or PostgreSQL. Also, Drupal supports popular MySQL forks such as MariaDB and Percona. You should understand that each system may have different specifications regarding the security.
Also much depends on the fact where you keep the database. The easiest way (in terms of security) is installing the database on the same server where you have a website. However, this approach can have an impact on the whole system’s performance and for this reason server administrators may decide to move the database on the separate server. This is especially true for high-loaded applications.
The first thing that you should do after finishing with the configuration of the server environment is checking if your infrastructure is robust enough and it can’t be easily broken by a DoS attack. In fact, even at the peak of its workload, the server should have some reserve of resources.
As I mentioned before database security settings can be very specific depending on the chosen database server. Within this article, let's look at some general measures:
- Database access
If the database is installed locally, you can disable the access to it from the network. If your database is on the separate server, it should be possible to set what IP address it will listen to. In case of sharing LAN between the web server and the database server set only a LAN IP address (not accessible via the Internet). It can be done by editing the my.conf file. Below is an example of the configuration when you use the same server for the database and the website.
- Databases, users, and permissions
Review your databases, users, and permissions in order to find any security bottlenecks. Don’t give users more rights than they actually need.
- PHPMyAdmin and similar tools
Make sure that you disable graphical tools for working with the database after using them. If you plan to continue using these tools, try to make an access to them as difficult as possible. For example, you can restrict an access to PHPMyAdmin by .htaccess and allow the access from certain trusted IP addresses. Besides, instead of using server applications you can try some local instruments like MySQL Workbench.
Drupal has a quite complex architecture. To ensure the safety of this complex system, it’s better to divide all the related work into small parts. During this operation, you will encounter a set of tasks that need to be done only once (set file permissions, configure the settings.php file, etc.). There will be some tasks that require periodic attention (update Drupal and modules). Perhaps others will require you to work closely with the Drupal community.
Here are the two key moments that you should keep in mind:
- Ensuring the Drupal security isn’t an easy thing but it’s very important for any website. So, you must definitely work on this.
- The security requires a constant attention from your side.
Make sure that a web server has no writing permissions on Drupal files. Writing permissions may only be needed for cached files, uploads, sessions and temporary directories. The following command grants a write access to the public files directory (Ubuntu/Debian):
$ chown -R www-data:www-data sites/default/files
If your website allows to upload files, pay attention to how you can secure the process of working with these files. Allow only certain file types to be uploaded. Relatively safe are text files and pictures. However, this does not change the fact that users can upload malicious code like a file with a .jpg or .txt extension. To avoid this problem you can try to install the ClamAV module which scans uploaded files for viruses and other malicious code.
The settings.php file
After the initial install, make sure that the settings.php file has no write permissions. Information about this can be found on the Status report page (admin/reports/status in Drupal 8).
In the settings.php file you can set one important option which prevents your website from thinking it is someone’s else. This type of attacks is called HTTP POST Header attacks. To protect a Drupal 7 website against them add the base URL parameter to your settings:
$base_url = 'http://www.example.com';
The similar thing in Drupal 8 is the trusted hosts array:
$settings['trusted_host_patterns'] = [ '^www\.example\.com$', ];
To generate an extra random data Drupal uses salt. Salt is also specified in the settings.php file. For enhanced security, you may put this value to some file which is located outside of the website root. In Drupal 7:
$drupal_hash_salt = file_get_contents('/home/example/salt.txt');
And in Drupal 8:
$settings['hash_salt'] = file_get_contents('/home/example/salt.txt');
Drupal provides a mechanism for monitoring a status of your website. Here I mean Recent log messages and Status report pages. Try to check these pages regularly and fix issues found. The Status report page is very useful, especially after a website installation. For example, it can inform you if you forgot to add the trusted hosts settings or there is a write access to the settings.php file. Some types of suspicious activities can be traced simply by looking at the Recent log messages page. As an example imagine a situation when you notice a surge in a registration of new users.
Don’t forget to disable the display of PHP errors. They should not be visible to ordinary users. Although you may see these errors on the Recent log messages page keep in mind that it doesn’t catch all PHP errors. So, check your server log files sometimes.
Changes in Drupal core and contributed modules
This part is about the possible hacks of the Drupal core and contributed modules. Actually, it’s a well-known fact that new developers may cut corners and put their code or some changes directly into Drupal core or the installed contributed modules. This can potentially lead to unpredictable behavior of Drupal itself, as well as to the appearance of vulnerabilities.
To veer away from these problems I recommend to use the Hacked! module. This module scans the currently installed Drupal, contributed modules and themes and compares everything with appropriate versions from drupal.org. If you have the Diff module installed, Hacked! will inform what exact lines were changed. All this makes the Hacked! module a valuable analytical tool for any website.
Users and permissions
Drupal has an intuitive and customizable permissions model. A permission is the simplest element of such system. A set of permissions can be grouped by a role. Then this role may be assigned to the particular users. New permissions and roles may appear during an update of Drupal core and contributed modules. You should periodically check (for example, after updating) which roles are assigned to each user on your website and what permissions are included in these roles. Try to minimize sets of permissions that are included in each role. Don’t give users more permissions than they really need.
A good security practice is a use of a non-standard username (e.g. not admin or root) for user/1 because an attacker will check standard variants in a first place. For greater security, it’s even possible to completely disable the user/1 account.
Another good thing is checking activities of users on your website and lock inactive accounts. The User Expire module provides an ability to define a date on which a specific user account will be locked. Also, it can lock accounts that are inactive for a certain period of time.
Depending on your needs you may find a lot of useful security modules on drupal.org. Here is just a brief list some of them:
In this article, we reviewed a number of practices aimed at securing your website. The review also covers all parts of the necessary infrastructure - from the common server settings to the specific use cases of some Drupal modules.
Many people neglect to monitor the security of their sites and server infrastructure until there are obvious problems. Although even observance of a number of simple rules would help to avoid their appearance. So be patient and always keep an eye on the security of your system. Good luck!
If you need any help, just request a free consultation!