Site icon GetPageSpeed

Magento Chmod – Secure Permissions for Magento 1.x

Magento Chmod and Chown

Magento Chmod and Chown

There is no point setting up something if it’s not secure. There are millions of bots who scan Magento stores for vulnerabilities. Set up your Magento store securely and you will have no outages caused by hackers. You will also have a good profit from your secure store.

This guide is for those people who know how to set up servers properly. This implies that:

Secure file permissions for a Magento website

Ownership (chown)

Everything should be owned by the website user: i.e. chown -R foo:foo.

In the standard setup, files are uploaded via SFTP by the website user.
PHP-FPM runs under that same user, so the website owner can always access the website files.
And thus, the PHP engine can access them too.
That is, provided that the site user will not revoke his own permissions for security or by mistake.

The website user can always read all the website’s files in this setup.
However, incorrect chmod settings might prevent it and pose a security risk.

The following are the rules for the secure chmod setting of website files.

Rule of thumb for the owner chmod bit, (the first octal number)

The corresponding letter for this chmod bit is u=....

For directories

For files

Rule of thumb for group chmod bit, (the middle octal number)

The corresponding letter for this chmod bit is g=....

For directories

For files

Rule of thumb for the other chmod bit, (the last octal number)

The corresponding letter for this chmod bit is o=....

Set it to 0 always!

Example

We have a directory with static files only: /var/www/example.com/httpdocs/News

We got chmod 750 for the directory (remember the last one is 0 always)

We apply the same rules from above for the files within that directory, and we get the correct chmod for them: 640.

Secure Magento after going live

For Magento 1.x website with standard directory structure, the following may be applied after the website goes to production.
Note! This is “lockdown” chmod – the website user won’t be able to write to the Magento core for security.
For more information read the manual.

The only major additions from the manual that we have here are giving read access to group (webserver) for media directory (since web server runs under a different user)

The following commands will cause a period of downtime while running because we start by applying the strictest permissions and later relaxing them with each command.
Also, NGINX might have to be restarted if open file cache is enabled (it might cache inaccessible status while the commands are running and visitors accessing).
We start from 400 (files) and 500 (dirs), which is equivalent to u=rX,g=,o=.
This permission allows only reading all directories and files to the PHP-FPM user.
Then we level up these permissions where needed, using letter syntax of chmod as well.
Letter chmod convention is the most useful for gradual permission increase:

# initial chmod:
chmod -R u=rX,g=,o= .
# in media directory, PHP-FPM should be able to create files (e.g. image upload), and NGINX to read them:
chmod -R u+w,o+rX media
# in var directory, PHP-FPM typically would create files, but there is nothing for NGINX to serve/read from there, thus:
chmod -R u+w var
chmod u+wX includes
chmod u+w includes/config.php
# Cron script should always be executable
chmod +x cron.sh
chmod g+r favicon.ico sitemap.xml
chmod -R g+rX errors errors/default
chmod -R g+rX errors/default/{css,images}
find js ! -name '*.php' -exec chmod g+rX {} \;
find skin ! -name '*.php' -exec chmod g+rX {} \;
# finally make sure that directory itself is accessible to nginx (group):
chmod g+rX .

The X letter in chmod application commands stands for applying execution(traversal) permission only to directories.

The lockdown chmod, in general, is prone to NGINX error:

rewrite or internal redirection cycle while processing “/index.php” is possible with this config

See related post about it for adjusting your NGINX to be more friendly to lockdown chmods.

Our lockdown permissions are extreme because we whitelist a handful of directories and files accessible to NGINX.
Everything else is unreadable for security reasons, which is a great security measure. Overall we have ensured that:

Naturally, if there is an additional directory with images, CSS files, etc. i.e., treat it as media:

chmod -R u+w,o+rX <some other dir with static files>

To identify such directories which contain static files, run:

find . -type f -name '*.jpg' - name '*.css' -printf '%h\n' | sort -u

The only downside of the above approach is the actual downtime during its application.

To make for a no-downtime lockdown (which might result in a less secure chmod overall), you should “inverse” the commands to mostly remove permissions instead of setting exact ones.
First, set permissions to the ones allowing both NGINX and PHP-FPM users to read the files, then gradually make them more strict:

chmod -R u=rwX,g=rX,o= . # this sets dirs to 750, files to 640 (allow write to PHP anywhere, NGINX read everywhere)
chmod g= includes # disallow NGINX from reading the includes dir
find . -type f ! -name 'index.php' -name '*.php' -exec chmod u-w,g= {} \; 
chmod u-w,g= cron.sh # same
chmod -R g= var # there is nothing for NGINX to read there

Note that for PHP files we disallow the website user from modifying them, by removing the write permission (-w).
NGINX user is furthermore restricted to not being able to even read those files with the exception of index.php files.
This is an important gotcha. For directives like index index.php, NGINX has to check the files for existence.

Alternatively, you can

Lock down chmod of PHP files (most important)

We finalize by preventing PHP from changing our chmod back.

This needs to be run by a sudo user:

sudo find . -type f -name "*.php" -exec chattr +i {} \;

On websites with multiple SSH users per site

Run commands above first.
Then, before accessing Magento via browser for the first time, run:

find var/ -type d -exec chmod g+s {} \; 
find media/ -type d -exec chmod g+s {} \;
chmod g+s includes
chmod g+s includes/config.php
Exit mobile version