Securing file permissions and ownership

Last updated on
4 February 2024

Introduction

If you don't know how Linux permissions work, you must read the following documentation: https://www.linuxfoundation.org/blog/blog/classic-sysadmin-understanding-linux-file-permissions

The server file system should be configured so that the web server (e.g. Apache) does not have permission to edit or write the files which it then executes. That is, all of your files should be 'read only' for the Apache process, and owned with write permissions by a separate user.

Note that this whole article is about "defense in depth". Drupal can run quite safely with permissions a little "looser" than they should be. But if an administrator account is compromised by an attacker or an attacker gains the ability to execute arbitrary code then the configuration below will limit their ability to further exploit your site.

Caution: Individual Results will Vary

Bear in mind that the process of securing files varies depending on individual server configuration. Always consult your server's documentation for further guidance. The methods for securing file permissions described in this guide assume you are a server administrator with root access to the server.

Site administrators using a Shared Hosting provider commonly lack this level of access and will find many of the methods that follow to be inaccessible due to insufficient privileges. Users of Shared hosting providers should consult that provider's documentation or seek professional assistance.

Automated Tools to Set Permissions

The File permissions module allows you to automatically set up correct file permissions in your Drupal instance. It uses Drush commands. Most importantly it maintains correct permissions on those directories. That module requires a full Root access to your server. Because this is all about permissions. This module will likely work with most hosting suppliers such as dedicated or vps. It would not work on shared hosting without full Root access.

The Drupal Fix Permissions repository provides a Bash script to automatically set up correct file permissions on Drupal installations. It requires full Root access to change ownership but it can be easily configured to be called with sudo, so regular users can safely use it. The script finds the files and folders that require a fix, improving performance on large installations where only a few items need their ownership or permissions changed. It also allows to declare content folders external to the Drupal root that need to be fixed. It will likely work with most hosting given that root or adequate sudo configuration is in place. It would not work on shared hosting without full Root access or the right sudo configuration.

Automated Tools to Verify Permissions

As a quick test to confirm whether your site is secure or not you can run the Security Review module. However, this module may from time to time report false positives. To avoid being confused by these you need to check the module's issue queue to see if there any open issues that are about false positives.

Configuration examples

For example, on many systems, the Apache process runs as a user called "www-data" that is in a group called "www-data". This user should be able to read all of the files in your Drupal directory either by group permissions or by "other" permissions. It should not have write permissions to the code in your Drupal directory. If you use features of Drupal which require the "files" directory, then give the www-data user the permission to write files only in that directory.

The following is an example file listing of a safe configuration showing two files in a site where uploaded files are stored in the "files" directory. In order to see the file permissions set for your setup, go to the command line and type: ls -al.

drwxrwx---  7 www-data    greg-group  4096 2008-01-18 11:02 files/
drwxr-x--- 32 greg-user   www-data    4096 2008-01-18 11:48 modules/
-rw-r-----  1 greg-user   www-data     873 2007-11-13 15:35 index.php

In the above example, the web server user has the ability to write in the files directory, any users in the group "greg" can read and write the data as well, but other users are not allowed to interact with that data. The "index.php" file (representative of all code files) can be edited by "greg" and can be read by the www-data group (we assume the www-data user is in the www-data group). No other users can read that file. This is a fairly secure method of configuring your site. You generally don't want random users who have the ability to read files on your server to see inside those files, hence the last three permissions are --- instead of r-x.

Below is an insecure setup:

NOTE: THIS IS AN INSECURE CONFIGURATION
drwxrwx---  7 www-data  www-data  4096 2008-01-18 11:02 files/
drwxrwx--- 32 greg-user www-data  4096 2008-05-16 11:48 modules/
-rw-rw-rw-  1 www-data  www-data   873 2007-11-13 15:35 index.php

This configuration allows the www-data user to edit the index.php file (and since it is representative of other files, we assume every file that makes up the Drupal site). This configuration is dangerous for the reasons outlined below. If you are using a configuration like this, please change it immediately to be more like the first version. Instructions for making the necessary changes are given below for Linux Servers.
 

How insecure permissions are a problem

If you allow your site to modify the files which form the code running your site, you make it much easier for someone to take over your server.

Worst case scenario: a file upload tool in Drupal allows users to upload a file with any name and any contents. This allows a user to upload a mail relay PHP script to your site, which they can place wherever they want to turn your server into a machine to forward unsolicited commercial email. This script could also be used to read every email address out of your database, or other personal information.

Undesirable scenario: if the malicious user can upload a file with any name but not control the contents, then they could easily upload a file which overwrites your index.php (or another critical file) and breaks your site.

Undesirable scenario: if the code allows users to see the contents of files, attackers could see information which might reveal potential attack vectors.

If you are a sysadmin

Disclaimer: Don't risk following these instructions blindly; each system has its own peculiarities and, because of that, the instructions here MUST be altered to suit your needs. All of the instructions here are aimed at people who are familiar with filesystem permissions and know exactly what all the commands written here mean. If you try to follow these instructions without paying full attention to what you are doing, you are very likely to get into trouble. These instructions are designed to alter filesystem permissions as a root-level user, so tread carefully!

Note for hosted Drupal installations

This installation method presumes one shared drupal core and many subdomains installed under it. So suppose you are the owner of a hosting service that has a Drupal installation already pre-configured and you want to sell a hosted Drupal site with pre-configured Drupal core to your clients. So when you sell it, you create their user on the server and let them configure their own Drupal site just entering their site's address to open the install page. The way this document suggests the configuration, it will prevent customers from modifying and accessing the Drupal core files and other customer's sites files and directories.

It is important to notice that the user ownership of Drupal's core directories/subdirectories and files is given to the user who administers Drupal (usually root) and group ownership is given to the group your apache is running on. For files and directories inside the "sites" directory the user who is hosting the site on your server is their owner. One way to do this is to delete the "sites" directory under Drupal's root directory and make it a symbolic link to /home or another path you use to store user's home directories. That way, if you create user names that matches the customer's site URL, no permission will need to be changed. The only thing to be done is to change the directory group ownership to the group your apache is running on.

$ cd /path_to_drupal_installation
$ mv sites/* /home
$ rmdir sites
$ ln -s /home sites
$ useradd www.example.com
$ chown -R www.example.com:www-data /home/www.example.com

The permission required by Apache is given through group permission and others have no access at all to any files and directories on a Drupal installation. Don't give any permissions to "others", otherwise if your system is hacked through a user's weak password, the hacker will be able to access all files and directories of all installed sites on your server, not only the one invaded. Even a read-only permission must be avoided. Remember that the user name and password to connect to the database for each site are stored in settings.php. Worse still, if you give write permission to others, the hacker will be able to alter files to damage your site or upload malicious scripts to your server.

The instructions in this guide assume a non-hosted installation, so modify the ownership to match your situation as necessary, e.g. where you see "greg" in these instructions, replace "greg" with the name of the user (often root, but not necessarily) who administers your installation of Drupal.

Linux servers

Permissions for files and directories on a Linux system are adjusted using the chmod command. User-owner and group-owner identity for files and directories are adjusted using the chown command.

The code below demonstrates one method for changing the ownership and permissions of files and directories in the Drupal Root directory to confirm ownership and permissions to the recommendations above. We assume in the example below that the user greg is part of the greg group and that user greg is the site owner. We also assume that you are running Drupal on a server that is not in a hosting environment which provides website hosting services to multiple customers.

Composer is used to install Drupal and manage dependencies thanks to the drupal/recommended-project package. It creates a new Drupal site with a "relocated document root". This means that the files "index.php" and the "core" directory and so on are placed inside a subfolder named "web" rather than being placed next to "composer.json" and the "vendor" directory at the project root.

The following commands should be run from inside this relocated document root, for example "/var/www/example.org/public_html/web", used in the example below.

The project root "public_html" folder contains composer.json, "vendor", and "web".

Warning:
Make sure you run the following commands from inside your Drupal's installation directory! If you run these commands from any other directory, you either will not make changes to all of the Drupal installation files and directories or you will make changes to files and directories other than those in the Drupal installation. Neither alternative is your goal.

$ cd /var/www/example.org/public_html/web
$ chown -R greg:www-data .
$ find . -type d -exec chmod u=rwx,g=rx,o= '{}' \;
$ find . -type f -exec chmod u=rw,g=r,o= '{}' \;

Note: Within a CentOS environment, you may need to use the apache group instead of the www-data group, which will change your second line to:
$ chown -R greg:apache .

The second command makes user greg the user-owner and group www-data the group-owner of all files and directories in Drupal's root directory and all subdirectories and files in those subdirectories (the -R switch means recursive). Note that in a multiple-customer hosting environment, the user-owner of the Drupal files and directories should be root.

The third command in the example finds all directories and subdirectories in Drupal's root directory and executes the chmod command on all of those directories and subdirectories (-type d means filesystem entities that are directories). The command changes the permissions to read, write and access for user greg and read and access for users in the www-data group. Users who are not greg and not in the www-data group cannot read, write, or access the directories or subdirectories in the Drupal root directory. In numeric notation, the permission assigned to these directories and subdirectories is 750.

The fourth command finds all files in the Drupal root directory and its subdirectories and changes the permissions on those files to read and write for the user greg and read only for the www-data group. Other users have no access to these files. The numeric notation for this set of permissions is 640.

For the "files" directory in the sites/default directory and any other site directories in a multi-site installation, the permissions are slightly different because the www-data user must have write permission to the directory:

$ cd /var/www/example.org/public_html/web/sites
$ find . -type d -name files -exec chmod ug=rwx,o= '{}' \;
$ find ./*/files -type d -exec chmod ug=rwx,o= '{}' \;
$ find ./*/files -type f -exec chmod ug=rw,o= '{}' \;

The second command above finds all subdirectories named files below the sites directory and changes the permissions for the user-owner and the group-owner to read, write, and access. All other users cannot read, write to, or access these files subdirectories.

The "for" loop above is written for an sh-style shell (sh, bash,ksh). If you use csh or tcsh, type bash before executing the command. These commands in the loop give read, write, and access permissions to user greg and group www-data to all subdirectories and files within the files but not access to other users. The numeric permissions code is 770.

Remember that any newly installed module/theme or whatever add-on must have its permissions changed too. It's better to do this BEFORE installing the module, theme, or add-on in its appropriate Drupal directory.

Windows servers

By default, Apache runs in the built in SYSTEM account. So all you have to do is change the permission in a way that only the SYSTEM account, the administrators group and the user greg have access to the Drupal root directory, subdirectories and files (assuming greg is the site owner).

You should exclude all other users and groups from the ACL. For the SYSTEM account give read only access to all Drupal directories, subdirectories and files except for the "files" directories which require write permission. For the user greg give read, modify and write permissions. And for the administrators group give complete access. Go to the Drupal root directory, right click on it, go to properties and then security.

Make use of permission inheritance to make things easier for yourself. And remember that any newly installed module/theme or add on must have its permissions changed too. It's better to do this BEFORE installing it in its appropriate Drupal directory. Permission inheritance is done automatically by Windows.

Special considerations for settings.php

The settings.php file contains the database password and username in plain text and, once created, must be set so that only appropriate users can read it. That usually means removing read permissions for the "other" user.

Summarizing the permissions

  • drupal_admin: the user on the server that administrates Drupal, not necessarily root (and should not be).
  • site_admin: the owner of the hosted site (a customer)

Ownership

Core modules/themes files and directories
drupal_admin:www-data
Hosted sites modules/themes/files files and directories
site_admin:www-data

Permissions

Core modules/themes directories
rwxr-x---
Core modules/themes files
rw-r-----
Hosted sites modules/themes directories
rwxr-x---
Hosted sites modules/themes files
rw-r-----
Hosted sites "files" directory
rwxrwx---
Hosted sites files under "files" directories
rw-rw----
Hosted sites subdirectories under "files" directories
rwxrwx---

Warning:
Follow this guide exactly as it is to make your Drupal installation as secure as possible. This guide was tested and works. If something goes wrong with your installation, review the steps -- possibly you missed something. If it really doesn't work, post a comment in the Discuss section.

Help improve this page

Page status: No known problems

You can: