Question

I'm gearing up to deploy a Drupal 7 site and I can't find any documentation about what the recommended security-conscious file and directory permissions should be set to.

Specifically default/files/ (also sub directories?), settings.php, .htaccess and anything else I should be aware of.

Was it helpful?

Solution

Your web server should be able to read all of the files but not write to them. If your site involves uploading files then give the server permission to write to that one folder only.

More information on how to set that up, as well as some things that can happen if you don't, is available in the Drupal docs.

OTHER TIPS

That drupal page like so many is very long and confusing. But it contains this post by Jason, who hit the nail on the head:

Posted by Jason Sale on November 1, 2010 at 12:40pm

Thanks for writing this and everything, but all that I and 99% of people reading this page really want is a list of numbers next to a list of folders.

  • /default on 755
  • /default/files including all subfolders and files on 744 (or 755)
  • /default/themes including all subfolders and files on 755
  • /default/modules including all subfolders and files on 755
  • /default/settings.php and /default/default.settings.php on 444

My practice around creating a new Drupal site on a server is to have a user that is a part of the web server (typically Apache) group, and have that user own all the Drupal files. On Ubuntu, these are the commands to get that set up:

# Create a new example user, setting up /var/www/example as their home dir.
useradd -s /bin/bash -d /var/www/example -m example

# Now add that user to the Apache group. On Ubuntu/Debian this group is usually
# called www-data, on CentOS it's usually apache.
usermod -a -G www-data example

# Set up a password for this user.
passwd example

Once I have that set up, I'll log in as that user and install Drupal at /var/www/example/docroot or similar, and then create the files directory by hand and copy over the settings.php file. Since we log in as our example user before copying in Drupal, our file ownership and permissions should automatically be properly configured on all the core Drupal files and scripts (including .htaccess files).

su - example
cd docroot
cp sites/default/default.settings.php sites/default/settings.php

# Temporarily give the web server write permissions to settings.php
chgrp www-data sites/default/settings.php
chmod g+w sites/default/settings.php

Now let's set up the files directory.

# Create the directory.
mkdir sites/default/files

# Now set the group to the Apache group. -R means recursive, and -v means 
# verbose mode.
chgrp -Rv www-data sites/default/files

Next we'll set up permissions so that the web server can always write to any file that is in this directory. We do this by using 2775 in our chmod command. The 2 means that the group id will be preserved for any new files created in this directory. What that means is that www--data will always be the group on any files, thereby ensuring that web server and the user will both always have write permissions to any new files that are placed in this directory. The first 7 means that the owner (example) can R (Read) W (Write) and X (Execute) any files in here. The second 7 means that group (www-data) can also R W and X any files in this directory. Finally, the 5 means that other users can R and X files, but not write.

 chmod 2775 sites/default/files

If there are any existing files in this directory, be sure the web server has write perms on them.

 chmod g+w -R sites/default/files

Now Drupal is ready to be installed. When finished, it is VERY important to come back to settings.php and ensure that all users only have read permissions.

 chmod 444 sites/default/settings.php

That's it! This set up ensures you avoid any situations where either the user that owns the directory or the web server can't write/change/remove files in the files directory.

The Drupal files folder should be writable by the webserver. The safest way to do that is to change the group and make it group writable, like this:

chgrp www-data sites/default/files
chmod g+w sites/default/files

The file upload folder aside, the safest is chmod 644 for all files, 755 for directories.

This could be accomplished like this (when run in the Drupal-site folder, the . is for current path):

find . -type f | xargs chmod 644
find . -type d | xargs chmod 755

Remember that you will need to set chmod g+w again after running the above command, since those will reset the chmod on all files and folders.

Any advice to "chmod blah" or "chown X" is meaningless without knowing: what the default user:group is on the files and what user and groups your webserver runs as.

The Drupal Docs others have linked to are quite good on the topic but one other resource is the Security Review Module which helps ensure you've got everything set properly.

I will reply considering the case the files are created on the server using FTP, using credentials different from the one under which is the web server runs (normally, Apache runs as nobody/nobody). This means that the user who owns the files manually created before running the Drupal installer (which includes also the files uploaded on the server from the Drupal archive) is not the user used to run the web server (neither the username or the group matches). This scenario applies also to the case where those files are created using SSH.

  • The settings.php file must be writable from the Drupal installer, but once the installation is done it is suggested to make it read-only (the installer suggest that, and Drupal will periodically check if the file is really read-only). In the scenario I am describing, the permission of this file should at least be 644.
  • The .htaccess files (which are present in at least two places) should have the permission 644. The user who created the file should still be able to overwrite the file, in the case a next version of Drupal comes with an .htaccess file that has been updated (it happened already once, when it has been added a line to that file to avoid a security issue). It is also possible to set the permissions to 444, but in that case, the permissions should be changed back to 644 when the file needs to be updated.
  • The directory containing the files created by the modules (the default/files directory) must be (for the user that is assigned to the web server processes, which is then the user assigned to to the PHP scripts running on that web server):
    • readable
    • writable
    • traversable (the modules must be able to reach default/files/<directory-used-by-the-module>/<sub-directory-used-by-the-module>)

Recommended file/directory permissions:

  • Drupal webroot should be world readable (see: updater.inc): 0755
  • for public upload directories: 0755 or 0775
  • for private upload directories: 0750 or 0770
  • for public uploaded files: 0644 or 0664
  • for private uploaded files: 0640 or 0660
  • for .htaccess within upload directories (see: file_create_htaccess()): 0444 (default) or 0644
  • for settings.php read-only for all (and other confidential files): 0440
  • for all other web directories: 0755
  • for all other web files: 0644

Recommended file/directory ownership:

  • owner of all upload directories/files should be set to Apache user,
  • owner of all web/sources directories/files should be set to non-Apache user,
  • (optionally) group of all sources should be set to Apache group,

Here are the variables which control default dir/file permissions for new items:

file_chmod_directory: 0775
file_chmod_file: 0664

Here is some script for fixing permissions: fix-permissions.sh


Read more:


Here is script which I'm using to fix permissions on remote host for public/private directories:

#!/bin/sh -e
# Script to correct public/private directory and files permissions.
[ -z "$1" ] && { echo Usage: $0 @remote.dst; exit 1; }

DST="$1" && shift
GET_HTTP_GROUP='ps axo user,group,comm | egrep "(apache|httpd)" | grep -v ^root | uniq | cut -d\  -f 1'

drush $* $DST ssh 'PUB=$(drush dd %files) && PRIV=$(drush dd %private) && AGROUP=$('"$GET_HTTP_GROUP"') && chgrp -vR $AGROUP $PUB $PRIV && chmod -vR u+rwX,g+rwX,o+rX $PUB $PRIV'

Note: Above code will try to retrieve Apache group and set it to GET_HTTP_GROUP variable.

This shell script is found at the bottom of this page: https://www.drupal.org/node/244924

I run it occasionally to ensure that my permissions are set up correctly.

#!/bin/bash
# Help menu
print_help() {
cat <<-HELP
This script is used to fix permissions of a Drupal installation
you need to provide the following arguments:
1) Path to your Drupal installation.
2) Username of the user that you want to give files/directories ownership.
3) HTTPD group name (defaults to www-data for Apache).
Usage: (sudo) bash ${0##*/} --drupal_path=PATH --drupal_user=USER --httpd_group=GROUP
Example: (sudo) bash ${0##*/} --drupal_path=/usr/local/apache2/htdocs --drupal_user=john --httpd_group=www-data
HELP
exit 0
}
if [ $(id -u) != 0 ]; then
  printf "**************************************\n"
  printf "* Error: You must run this with sudo. *\n"
  printf "**************************************\n"
  print_help
  exit 1
fi
drupal_path=${1%/}
drupal_user=${2}
httpd_group="${3:-www-data}"
# Parse Command Line Arguments
while [ $# -gt 0 ]; do
  case "$1" in
    --drupal_path=*)
      drupal_path="${1#*=}"
      ;;
    --drupal_user=*)
      drupal_user="${1#*=}"
      ;;
    --httpd_group=*)
      httpd_group="${1#*=}"
      ;;
    --help) print_help;;
    *)
      printf "***********************************************************\n"
      printf "* Error: Invalid argument, run --help for valid arguments. *\n"
      printf "***********************************************************\n"
      exit 1
  esac
  shift
done
if [ -z "${drupal_path}" ] || [ ! -d "${drupal_path}/sites" ] || [ ! -f "${drupal_path}/core/modules/system/system.module" ] && [ ! -f "${drupal_path}/modules/system/system.module" ]; then
  printf "*********************************************\n"
  printf "* Error: Please provide a valid Drupal path. *\n"
  printf "*********************************************\n"
  print_help
  exit 1
fi
if [ -z "${drupal_user}" ] || [[ $(id -un "${drupal_user}" 2> /dev/null) != "${drupal_user}" ]]; then
  printf "*************************************\n"
  printf "* Error: Please provide a valid user. *\n"
  printf "*************************************\n"
  print_help
  exit 1
fi
cd $drupal_path
printf "Changing ownership of all contents of "${drupal_path}":\n user => "${drupal_user}" \t group => "${httpd_group}"\n"
chown -R ${drupal_user}:${httpd_group} .
printf "Changing permissions of all directories inside "${drupal_path}" to "rwxr-x---"...\n"
find . -type d -exec chmod u=rwx,g=rx,o= '{}' \;
printf "Changing permissions of all files inside "${drupal_path}" to "rw-r-----"...\n"
find . -type f -exec chmod u=rw,g=r,o= '{}' \;
printf "Changing permissions of "files" directories in "${drupal_path}/sites" to "rwxrwx---"...\n"
cd sites
find . -type d -name files -exec chmod ug=rwx,o= '{}' \;
printf "Changing permissions of all files inside all "files" directories in "${drupal_path}/sites" to "rw-rw----"...\n"
printf "Changing permissions of all directories inside all "files" directories in "${drupal_path}/sites" to "rwxrwx---"...\n"
for x in ./*/files; do
    find ${x} -type d -exec chmod ug=rwx,o= '{}' \;
    find ${x} -type f -exec chmod ug=rw,o= '{}' \;
done
echo "Done setting proper permissions on files and directories"
Copy the code above to a file, name it "fix-permissions.sh" and run it as follows:
sudo bash fix-permissions.sh --drupal_path=your/drupal/path --drupal_user=your_user_name

Note: The server group name is assumed "www-data", if it differs use the --httpd_group=GROUP argument.

Also if you are running fastcgi, the php runs AS the user, and will have access to all files that the user has access to unless you deliberately try to avoid this.

This helped me with my OSX Permission issues. I found it in https://www.drupal.org/node/244924#comment-3741738 by protoplasm user. I was like him having issues after a migration.

[root@localhost]cd /path_to_drupal_installation/sites
[root@localhost]find . -type d -name files -exec chmod ug=rwx,o= '{}' \;
[root@localhost]find . -name files -type d -exec find '{}' -type f \; | while read FILE; do chmod ug=rw,o= "$FILE"; done
[root@localhost]find . -name files -type d -exec find '{}' -type d \; | while read DIR; do chmod ug=rwx,o= "$DIR"; done

There is a module called Security review which checks whether your site is secure or not. I also found a very good link to set site permissions.

Licensed under: CC-BY-SA with attribution
Not affiliated with drupal.stackexchange
scroll top