Securing file permissions and ownership (Drupal)

The server file system should be configured so that the webserver (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.
As a quick test to confirm whether your site is secure or not you can run the Security Review module.

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.

Configuration examples

For example, on many systems the Apache process runs as a user 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.

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 set-up, go to the command line and type: ls -al.

drwxrwx---  7 www-data greg      4096 2008-01-18 11:02 files/
drwxr-x--- 32 greg     www-data  4096 2008-01-18 11:48 modules/
-rw-r-----  1 greg     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:

drwxrwx---  7 www-data www-data  4096 2008-01-18 11:02 files/
drwxrwx--- 32 greg     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.

Quick lesson in permission’s numeric equivalents

Special numbers mean less than “read write execute”.
In general, special numbers like “4 means read, 2 means write, and 1 means execute” are less useful than “r means read, w means write, and x means execute.”

However, some folks/software need numbers so:

rwxrwx--- is also 770
The order represents user-group-other. More information on permissions can be found later in this document.

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

Note for hosted Drupal installations

It’s important to notice that the user ownership of Drupal’s core directories/subdirectories and files is given to the user who administrates 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. The best way to do this is to delete the “sites” directory under Drupal’s root directory and make it a symbolic link to /home or other 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
-R /home/

The apache permission is given through group permission and others have no access at all to any files and directories on a Drupal installation. Don’t give in any way permission to others, otherwise if your system is hacked through a weak password of a given user, the hacker will 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 database user name and password for each site are stored in settings.php. Worse, if you give write permission to others, the hacker WILL alter files to damage your site or upload malicious scripts to your server.

The instructions in this guide assumes a non hosted installation, so modify the ownership as needed. So where you see greg, can be replaced by the user who administrates Drupal, usually root, but not necessarily.

Follow this guide exactly as it is to make your Drupal installation as more 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 with your doubt, we will fix this guide.

Linux servers

To set the permissions all at once you can issue these commands from the Drupal root directory. I’m assuming that greg user is part of greg group and that greg is the site owner. Make sure you run the following commands from inside Drupal’s root directory otherwise you will mess up all your filesystem’s permissions.

[root@localhost]cd /path_to_drupal_installation
[root@localhost]chown -R greg:www-data .
[root@localhost]find . -type d -exec chmod u=rwx,g=rx,o= {} ;
[root@localhost]find . -type f -exec chmod u=rw,g=r,o= {} ;

The second command will give ownership recursively on Drupal’s root directory for user greg and www-data group. Don’t do this if you are in a hosted installation. To the Drupal’s root files and directories the user root must be the owner, not greg.

The third command will find all directories and subdirectories on Drupal’s root directory and execute a chmod that will change the permissions to read, write and access for user greg, read only and access to www-data group and none to others. Summarizing: rwxr-x—

The fourth command will find all files inside Drupal’s directories and execute a chmod that will change the permissions to read, write for the user greg, read only for www-data group and none to others. Summarizing: rw-r—

Now for the “files” directories the permissions are slightly different because it must have write permission to the www-data group too:

[root@localhost]cd /path_to_drupal_installation/sites
[root@localhost]find . -type d -name files -exec chmod ug=rwx,o= '{}' ;
[root@localhost]for d in ./*/files
find $d -type d -exec chmod ug=rwx,o= {} ;
find $d -type f -exec chmod ug=rw,o= {} ;

These commands will give read, write and access for user greg and for www-data group and none to others(rwxrwx—) for all “files” directories inside Drupal’s “sites” subdirectory and will give read and write permission for user greg and group www-data and none to others (rw-rw—-) for all files found inside each “files” subdirectories.

Remember that any newly installed module/theme or whatever addon must have its permissions changed too, It’s better to do this BEFORE installing it in its appropriate Drupal directory.

Addendum on chmod non numeric permission representation

Meaning of the signs:
“+” add a permission to the ones already assigned
“-” revoke a given permission maintaining the others already assigned
“=” ignores the already assigned permissions and gives the ones listed
“u” = user
“g” = group
“o” = others
“a” = everybody (user, group, others)

For files:
r = read
w = write
x = execute

For directories:
r = list (read directory contents)
w = write
x = can access the directory. Whoever has not an x for a directory can’t make a cd to it.

Using chmod without numeric values makes it more human readable. Here some examples of how to use it:

chmod commands and results for a file with permissions rwxrwx— (770)
chmod human chmod numeric resulting permission
ugo=rwx 777 rwxrwxrwx
u-wx 470 r–rwx—
o+r 774 rwxrwxr–
g-wx,o+r 744 rwxr–r–
u-w,g-wx,o+r 544 r-xr–r–
g=,o=r 704 rwx—r–
a-wx 440 r–r—–

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, sudirectories 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 addon must have its permissions changed too. It’s better to do this BEFORE installing it in its appropriate Drupal directory. For those who use permission inheritance it’s 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, should 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 is the root.
  • site_admin: the owner of the hosted site (a customer)


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


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—

Script based on guidelines given above

If you need to fix permissions repeatedly then the following script will help you, it is based on the guidelines given above and performs some checks before any modification to ensure it is not applied on files/directories outside your drupal installation.

help=”nHelp: This script is used to fix permissions of a drupal installationnyou need to provide the following arguments:nt 1) Path to your drupal installationnt 2) Username of the user that you want to give files/directories ownershipnNote: “www-data” (apache default) is assumed as the group the server is belonging to, if this is different you need to modify it manually by editing this scriptnnUsage: (sudo) bash ${0##*/} drupal_path user_namen”if [ -z “${path}” ] || [ ! -d “${path}/sites” ] || [ ! -f “${path}/modules/system/system.module” ]; then
echo “Please provide a valid drupal path”
echo -e $help
fiif [ -z “${user}” ] || [ “`id -un ${user} 2> /dev/null`” != “${user}” ]; then
echo “Please provide a valid user”
echo -e $help
ficd $path;echo -e “Changing ownership of all contents of “${path}” :n user => “${user}” t group => “${group}”n”
chown -R ${user}:${group} .
echo “Changing permissions of all directories inside “${path}” to “750”…”
find . -type d -exec chmod u=rwx,g=rx,o= {} ;
echo -e “Changing permissions of all files inside “${path}” to “640”…n”
find . -type f -exec chmod u=rw,g=r,o= {} ;

cd $path/sites;

echo “Changing permissions of “files” directories in “${path}/sites” to “770”…”
find . -type d -name files -exec chmod ug=rwx,o= ‘{}’ ;
echo “Changing permissions of all files inside all “files” directories in “${path}/sites” to “660”…”
find . -name files -type d -exec find ‘{}’ -type f ; | while read FILE; do chmod ug=rw,o= “$FILE”; done
echo “Changing permissions of all directories inside all “files” directories in “${path}/sites” to “770”…”
find . -name files -type d -exec find ‘{}’ -type d ; | while read DIR; do chmod ug=rwx,o= “$DIR”; done

Copy the code above to a file, name it “” and run it as follows:
sudo bash your/drupal/path your_user_name

Note: The server group name is assumed “www-data”, if it differs modify it in the script code.

Leave a Reply

Your email address will not be published. Required fields are marked *