Securing Magento File & Directory Permissions

Securing Magento File & Directory Permissions

Dec 6

  • Created: Dec 6, 2010 1:40 PM

Securing Magento
By default most software packages are installed with the most lenient file/directory permissions and ownership. This is normally done for the sake of the software developer given that their software must be installed on a range of diverse systems with varying configurations. This article is meant to give you an overview of how to setup your Magento installation with the strictest of permissions for overall security’s sake.

When running Linux there are two main environments that you will find:

  1. PHP scripts that run via mod_php or equivalent and all scripts are executed as the webserver user. This means that when your script is running it can read (and sometimes write) with the same privilege level as the web server. This could allow cross-account snooping in shared hosting setups and is not ideal in a shared environment especially when it comes to e-commerce.
  2. PHP scripts that run as the user who owns the files themselves via an intermediate construct such as suPHP, PHP suEXEC, PHP-FPM etc. In this case your scripts run as you and is a more secure overall configuration when running on a shared server.

Running As The Webserver User (#1)

NOTE: These instructions are meant to be used with Magento Enterprise. If you are going to do the following with Magento Community Edition then this will effectively break the Magento Connect functionality. That said we’ve included a script to turn on and off these changes should you wish to use these instructions flexibly.

By default many shared and dedicated hosting companies run your scripts as the webserver user itself as stated above. It’s the operating system default on most Linux systems and while in a shared environment it’s not the most secure it can be partially remedied. This is done by limiting access via more strict file permissions which mitigates some of the inherent security issues. In dedicated hosting environments this method is actually desirable, mainly for performance reasons, and all of our dedicated and clustered Magento SIP plans use this method. None of the shared hosting caveats apply for dedicated servers given that the server is serving a single client.

These are the steps we take in plain English followed by the script commands:

  1. If you have access to change the ownership of files and directories (normally meaning you have root access) then set the user and group ownership of all files in the Magento directory to your local user. This may already be done in your environment and is simply a precaution for good measure to flush out any webserver owned files or directories.
  2. find </path/to/magento> \-exec chown youruser.youruser {} \;
  3. Change the Linux permissions for all files in your Magento base directory to readable and writable by the owning user (you) and readable only by everyone else. This is to get a baseline where the webserver itself can read all files. It will need read access in order to execute scripts and serve static content like images, CSS and Javascript files.
  4. find </path/to/magento> -type f \-exec chmod 644 {} \;
  5. Change the Linux permissions for all directories in your Magento base directory to list-able, file editable and navigable for the owning user and simply navigable for everyone else.
  6. find </path/to/magento> -type d \-exec chmod 711 {} \;
  7. The “media” and “var” directories require special handling since the webserver itself must be able to both read and create/edit files. This is where most instructions give away the farm and go straight for world editable permission on files and directories. We’ll take a least privileged approach by changing the Linux permissions for all directories to list-able, file editable and navigable by the owning user and just navigable by everyone else. We’ll also take the extra step of setting the Linux “group” permissions on the file so that anyone in the group can list, edit files and navigate the directories as well.
  8. find </path/to/magento/media> -type d \-exec chmod 775 {} \;
    find </path/to/magento/var> -type d \-exec chmod 775 {} \;
  9. We’ll do something similar for the files in the “media” and “var” directories as well. That is allow the owning user read and write permissions, the group user read and write permissions and everyone else simply read permissions.
  10. find </path/to/magento/media> -type f \-exec chmod 664 {} \;
    find </path/to/magento/var> -type f \-exec chmod 664 {} \;
  11. This step will also require either root level access or a flexible hosting company (like us). You will need to set the file and directory ownership for the “media” and “var” directories to be owned by the webserver and have group ownership to your local user. You could argue that this is backwards but for technical reasons involving how we calculate disk space usage this is how it’s recommend and done on our systems.
  12. find </path/to/magento/media> \-exec chown webuser.youruser {} \;
    find </path/to/magento/var> \-exec chown webuser.youruser {} \;
  13. This step again will require root access and/or a flexible host and is probably the least understood of all of the steps. In steps 5 and 6 we’ve setup a system whereby you are allowing the webserver access to read and write your files but in a way that is very specific – which is a good thing. We’ve done this on a specific set of existing files and directories. We need to ensure that future files and directories created follow an equal (or more strict) set of ownership and permissions. This is done by using some special features of Linux directories, namely the SUID and SGID bits. These bits, when set, tell Linux to inherit the ownership of the directory which immediately encompasses the file or directory being made. Simply, as Magento creates files and directories in “media” and “var” their ownership will mirror what we set in step 6.
  14. find </path/to/magento/media> -type d \-exec chmod u+s,g+s {} \;
    find </path/to/magento/var> -type d \-exec chmod u+s,g+s {} \;
  15. Finally, for a minimal amount of added protection against snoopers change the file permissions on the core Magento configuration files to be readable and writable by the file owner and readable by the group only.
  16. chmod 640 </path/to/magento/app/etc/*.xml>

Magento web user permissions script:

#!/bin/bash

if [ ! -f ./app/etc/local.xml ]; then
    echo "-- ERROR"
    echo "-- This doesn't look like a Magento install.  Please make sure"
    echo "-- that you are running this from the Magento main doc root dir"
    exit
fi

if [ `id -u` != 0 ]; then
    echo "-- ERROR"
    echo "-- This script should be run as root so that file ownership"
    echo "-- changes can be set correctly"
    exit
fi

echo -n "Enter the local UNIX account user (ftp user): "
read user
echo -n "Enter the local UNIX webserver user (normally 'apache'): "
read webuser

if [ ! `id -u $user` ]; then
    echo "-- ERROR"
    echo "-- No such user: $user"
    exit
fi

if [ ! `id -u $webuser` ]; then
    echo "-- ERROR"
    echo "-- No such user: $webuser"
    exit
fi

find . \-exec chown $user.$user {} \;
find . -type f \-exec chmod 644 {} \;
find . -type d \-exec chmod 711 {} \;
find ./media -type d \-exec chmod 775 {} \;
find ./var -type d \-exec chmod 775 {} \;
find ./media -type f \-exec chmod 664 {} \;
find ./var -type f \-exec chmod 664 {} \;
find ./media \-exec chown $webuser.$user {} \;
find ./var \-exec chown $webuser.$user {} \;
find ./media -type d \-exec chmod u+s,g+s {} \;
find ./var -type d \-exec chmod u+s,g+s {} \;
chmod 640 ./app/etc/*.xml

That’s all there is to it. Doing the above will give you some of the tightest permissions available on a Magento install.

Running As Your Local User (#2)

In shared environments this method is preferred given the extra level of security provided by Linux if the permissions are configured correctly as we’re going to do. All of our shared Magento SIP plans provide this environment and it is preferred given that is provides user-based permissions isolation so stricter ownership and file permissions can be used.

These are the steps we take in plain English followed by the script commands:

  1. If you have access to change the ownership of files and directories (normally meaning you have root access) then set the user and group ownership of all files in the Magento directory to your local user. This may already be done in your environment and is simply a precaution for good measure.
  2. find </path/to/magento> \-exec chown youruser.youruser {} \;
  3. Change the Linux permissions for all files in your Magento base directory to readable and writable by the owning user (you) and readable only by everyone else. This is to get a baseline where the webserver itself can read all files. It will need read access in order to serve static content like images, CSS and Javascript files. Unlike the method above we’ll be adjusting script permissions to be more stringent in step 4.
  4. find </path/to/magento> -type f \-exec chmod 644 {} \;
  5. Change the Linux permissions for all directories in your Magento base directory to listable, file editable and navigable for the owning user and simply navigable for everyone else.
  6. find </path/to/magento> -type d \-exec chmod 711 {} \;
  7. Wrench down permissions for all PHP scripts so that only your user can read them. This is ideal because only your user should need to know the contents of scripts.
  8. find </path/to/magento> -type f -name “*.php” \-exec chmod 600 {} \;
  9. Finally, and this is the nicest part about using this method, disable all access to your local configurations files for Magento except to yourself. Since the PHP scripts are the only thing that need to read these files and PHP is running as you then you can disable access to all others which is very nice!
  10. chmod 600 </path/to/magento/app/etc/*.xml>

Magento local user permissions script: –

#!/bin/bash

if [ ! -f ./app/etc/local.xml ]; then
    echo "-- ERROR"
    echo "-- This doesn't look like a Magento install.  Please make sure"
    echo "-- that you are running this from the Magento main doc root dir"
    exit
fi

if [ `id -u` != 0 ]; then
    echo "-- ERROR"
    echo "-- This script should be run as root so that file ownership"
    echo "-- changes can be set correctly"
    exit
fi

echo -n "Enter the UNIX user which the Magento scripts should run as: "
read user

if [ ! `id -u $user` ]; then
    echo "-- ERROR"
    echo "-- No such user: $user"
    exit
fi

find . \-exec chown $user.$user {} \;
find . -type f \-exec chmod 644 {} \;
find . -type d \-exec chmod 711 {} \;
find . -type f -name "*.php" \-exec chmod 600 {} \;
chmod 600 ./app/etc/*.xml

One Final Note

I’ve seen many instructions for web based software that states that files must be 777 permissions (read/write/execute permissions to all). This may be necessary for some directories but is rarely right for files. Permissions of 666 (read/write permissions for all) are adequate in these cases (if more strict permissions cannot be set). 777 permissions sets the execute bit on files as well which most web servers don’t (and shouldn’t) require in most cases. Setting 666 permissions simply says “read and write for all users” which isn’t great either but is more correct.

Permission reset script: (applicable to both methods above)

#!/bin/bash

if [ ! -f ./app/etc/local.xml ]; then
    echo "-- ERROR"
    echo "-- This doesn't look like a Magento install.  Please make sure"
    echo "-- that you are running this from the Magento main doc root dir"
    exit
fi

if [ `id -u` != 0 ]; then
    echo "-- ERROR"
    echo "-- This script should be run as root so that file ownership"
    echo "-- changes can be set correctly"
    exit
fi

echo -n "Enter the UNIX user which the Magento scripts should run as: "
read user

if [ ! `id -u $user` ]; then
    echo "-- ERROR"
    echo "-- No such user: $user"
    exit
fi

find . \-exec chown $user.$user {} \;
find . -type f \-exec chmod 644 {} \;
find . -type d \-exec chmod 711 {} \;
find . -type f -name "*.php" \-exec chmod 600 {} \;
chmod 600 ./app/etc/*.xml
  • mirek

    This is absolutely the best article on permission/ownership/security for Magento. I’ve been looking for something like that for last two years. It looks like no one was able to put together all these information in such a clear way. I followed so many articles and advices and none of them explain “why this and not that way?”. So, as a result I had to many 777’s and I believe this was the cause of some of my problems with security on shared server. I used published here reset script and it works perfectly fine for me. The one offered by Magento caused loading pages with errors and I wasn’t able to find out why. Thank you.

  • Pingback: Magento by syncwithus - Pearltrees()

  • http://www.facebook.com/profile.php?id=692865664 Pee Dee

    Hi,
    thanks for the most useful explaination on this topic, which I never quite understood fully. the script you linked to seems to have dissappeared, can you please re-upload? Thanks Paul

  • hadifarnoud

    files are not found

  • will_hough

    Files are fixed, thanks for letting us know.

  • Pingback: The 54 Most Useful Magento Articles of All Time | @nexcess()

  • Pingback: [Magento] Magento Code Snippets()

  • Pingback: Magento Code Snippets | Magento For Fresher()

  • Pingback: Magento Permissions - Aboudi()

  • mrartist

    This is great and perhaps the best thing I’ve found so far even in late 2014. It’s a shame somebody hasn’t created a simple GUI to do this for us by clicking some buttons (as well add any custom requirements) as we all seem to be struggling with the same problems.

    There’s one major points about this that I’d like to ask/check about:

    1) The lowest bit of code described as the “Permission reset script” is exactly the same as the script above it described as “Magento local user permissions script” – I suspect something has got lost/gone missing for the lower one.

    I assume the mention of this is at the top where you say “… we’ve included a script to turn on and off these changes should you wish to use these instructions flexibly.”

    Any chance you can reinstate the correct suggestions for the “reset” script – I assume by reset, that means reset for installing, before tightening things up again with the upper scripts?