Use a custom domain name as a way to secure your Magento administrative panel

After this year 2015 full of security issues (SUPEE-6482, SUPEE-6285,SUPEE-6237, SUPEE-5994, SUPEE-5344) we have seen that there is many websites which only use the custom routing to hide the administrative panel; it means, back-offices are available from the front webservers with a string in URL as element to identify you wants to access to the admin panel.

And by default this string is admin, a not very difficult element to find :).

In this case, we are not very far from default behaviour, and everyone can access from your website to your back-office login form. And if you do not have admin accounts automatic locking (like the community edition does) you encounter risks of brute force logging attempts. And if someone earn back-office access, he will:

  • delete your customers accounts?
  • close your websites?
  • Spam your customers?
  • Install an incompatible module from Magento connect which will break your site?

All these can affect your brand image.

But there is some ways to make more secure the Magento admin panel. One of them, its to use a custom domain name for your back-office: it has the main advantage to allow you to customize security rules.

Just a few of configuration are required. You’ll find them bellow.

This article expect that

  • Your Magento webserver is hosted on a unix debian like operating system.
  • Your webserver is Apache.
  • Your Magento website is defined in the /etc/apache2/site-available/magento.conf file
  • Your back-office is available on the HTTP protocol.
  • For now, you access to your back-office from the www.mywebsite.com/customadminpath URL.
  • You wants to move it to the URL admin.mywebsite.com/customadminpath

The Magento configuration inherit mechanism

Before talking about the procedure to switch your back-office to a custom admin URL, just few words about how Magento manage URLs.

Magento come with it’s own concepts, and one of them is the ability to manage multiples websites and their internationalization within stores views.

When you display a page on Magento, you are in a store view. If you try to load a configuration value from this view, Magento first check if you have defined something for this store view. If yes, it use this value. If not, it check if you have defined something for the related website. If not, it’ll use the value set for the global scope. A concept you probably already know if you use Magento.

Back-office is a particularity of this concept: even if back-office is a store view, there is no hierarchy: the configuration used by the back-office view are the values defined for the global scope.

Magento URLs are completely included in this configuration management:

  • admin URL is the URL defined on the scope default.
  • Your websites and stores views are the specificities defined for the related configurations levels.

So Magento configuration inherit mechanism offer everything to define a custom URL for your back-office. It should be a shame to do not use it. How can we migrate this configuration?

Configure a custom admin URL for your Magento back-office

Step 1: Ensure that your Magento front-office stores URLs does not use the configuration inherit mechanism

This step is required because if you still use the configuration inherit mechanism (eg: have just define the URLs on the global scope), when we’ll update the back-office URL your front office URLs will also be updated. it could be problematic 🙂

The configuration of the Magento URLs is managed differently for secure (http) and unsecure (https) part of your website. We start with the unsecure part.

1.1 – Ensure that your Magento unsecure store URL(s) does not use inherit configuration

1.1.1: Go to the Magento administrative panel which manage URLs configuration

This configuration panel is located in the System > Configuration > General > Web > Unsecure URL tab. You should see something like this:

Screenshot of the interface in the Magento administrative panel which allow to manage URLs of your websites and stores

1.1.2: Iterate on each store view configuration

On the top left of the page, you have the store view selector (the select box which allow to define on which store view you are currently editing the configuration). on my Magento, I have:
Screenshot of the selectbox which allow to choose on which scope we work

1.1.3: Uncheck the configuration values for your URLs

Check for each store views from this selectbox the configuration of your unsecure URLs: make sure that the “Use website” is unchecked like in the screenshot bellow.
Screenshot of the Magento admnistrative panel: checkbox allow to customize the scope you are updating
If not, uncheck it and save configuration.

Repeat this step for each of the store views available (in my case, en_uk, en_us, fr_fr and the french store view for the b2b website).

To check if everything is ok, flush the cache block from the administrative panel System > Cache Management and browse with your web browser all of your stores: your(s) catalog(s) must be still available(s).

Your websites and store views use now a dedicated configuration value for the unsecure URL.

1.2 – Ensure your secure store URLs does not inherit configuration

Repeat the steps 1.1.1, 1.1.2, and 1.1.3 for your secure URLs configuration (available from System > Configuration > General > Web > secure URL tab).

When you’ll finished, you can validate with your web browser (after flushing cache block cache mangement) that for each of your store views the customer accounts and checkouts are still available.

Step 2: Ensure that your Magento cookie policy is able to handle a new admin URL

Ok, now you do not use anymore the inherit mechanism for both http and https URLs. But it’s not yet finish with the configuration: for now, your cookie policy is able to handle both your front and back-office queries. But if we update our back-office domain name and leave the cookie policy as it, back-office could be unavailable. Wrong not?

We have to also update this domain name cookie configuration

This step is only required if you have for some of your store view(s) or website(s) defined a custom cookie domain. But by default, the cookie domain accept everything. If you have not updated it, you can go directly to step 3 but I think it’s however interesting to take time to check this configuration.

2.1 – Ensure that configuration for cookie domain for your front-office store views does not depends of the default cookie domain configuration

Go now in the menu System > Configuration > General > Web > Cookie Management and make sure that the value set for each store is like we have done for the URL management: For each store, uncheck the “use website” checkbox and save configuration.

Use a custom cookie domain for session cookie

We are now sure that our configuration for our front office store views is specific.

2.2 – Ensure that the cookie domain configuration for the admin is able to handle both new and current domain names

For the back-office scope (scope default), make sure to select a cookie domain value which is acceptable by both your new admin URL and your current URL: since we’ve not updated the admin configuration URL, we need to be able to browse back-office. And when we’ll update it, we must also be able to do it. If not, when we’ll update the admin URL, we won’t be able to connect to the back-office because session will not be available.

Cookie domain is configurable from the administrative panel on the fieldset General > Web > Session Cookie Management. Ensure that you’ll update configuration value for the default scope!

in this example we should set something like .mywebsite.com, witch match both admin.mywebsite.com and www.mywebsite.com.

If there is no shared domain name between current and the future back-office URL, you must set . as cookie domain. This is less secure, but it’ll work in each case.

After updating this configuration value, log out from back-office, close your browser, and log in a second time. You should still be able to browse back-office.

Step 3: Update Apache configuration to define your custom admin back-office URL

Now Magento is ready to accept a new URL for the back-office. Before setting this new value in Magento back-office, we have to update Apache configuration: if not, when we send a request to our webserver with the new URL admin.mywebsite.com, we’ll try to access to a webserver unknown by Apache and we have an unexpected answer.

A good starting point could be to copy your current front-office configuration file to a new one to define the specificities to the admin server:

root@your_web_server:~$ cp /etc/apache/sites-enabled/magento.conf /etc/apache/sites-available/magentoadmin.conf && sed "s|ServerName *www.mywebsite.com|ServerName admin.mywebsite.com|g" --in-place='.bak' /etc/apache/sites-available/magentoadmin.conf && ln -s /etc/apache2/sites-available/magentoadmin.conf /etc/apache2/sites-enabled

The file /etc/apache2/sites-enabled/magentoadmin.conf should contains something like this:

<Virtualhost XXX.YYY.ZZZ.TTT:80>
      ServerName admin.mywebsite.com
      DocumentRoot /a/path
      <Directory /a/path>
           # your magento configuration here
      </Directory>
</VirtualHost>

You should force Magento to load the admin panel when a request is sent to admin.mywebsite.com by using the following server variables in this file:

<Virtualhost XXX.YYY.ZZZ.TTT:80>
      ServerName admin.mywebsite.com
      DocumentRoot /a/path
      <Directory /a/path>
      # your magento configuration here
      # force loading the admin store
      setEnv MAGE_RUN_CODE admin
      setEnv MAGE_RUN_TYPE store
      </Directory>
</VirtualHost>

Don’t forget to check if everything is ok in your apache configuration with the following command:

user@your_web_server:~$ apache2ctl configtest

If the output is ok, restart apache with the following command:

root@your_web_server:~$ apache2ctl restart

Now, Your apache webserver know what to do if it receive a request for admin.mywebsite.com

Step 4: Resolve your new Magento administrative panel domain name

The final preparation step is to explain to your desktop or all required back-office users that http://admin.mywebsite.com must be managed by your webserver. If not, your browser can ask http://admin.mywebsite.com but don’t know where going to find the appropriate answer.

4.1 – Check that domain resolution for your future admin webserver is not fine enough

I’ll give you two methods to check if your Magento admin domain name resolution is able to handle your admin configuration domain name yet:

  • by ping command
  • using your browser.
4.1.1: Check your future admin domain name resolution using the ping command

Open a terminal from your computer, and ping your new admin hostname with the following command:

user@your_web_server: ping admin.mywebsite.com

If you have an output like this:

ping: unknown host admin.mywebsite.com

You have to configure a DNS resolution for your admin.

4.1.2: Check your future admin domain name resolution with your browser

You can also check if your browser is able to resolve it by opening a new window (or tab) and open the URL http://admin.mywebsite.com

If your browser tell you that it cannot resolve it, you’ll have to made the DNS resolution

Screenshot of chrome browser output when domain name resolution is not found

Screenshot of firefox browser output when domain name resolution is not found

4.2 – Set up your domain name resolution for your Magento future administrative panel

it can be done:

  • For you current desktop:
    • In your %windows_folder%/System32/Drivers/etc/hosts file if you are on windows.
    • In your /etc/hosts file if you are on Linux based distribution.
    • For MAC users, my bank loan have been refused, I don’t have MAC 🙂 (but I suppose it’s also in /etc/hosts file).
  • For different users:
    • In your DNS record.

After that, a

user@your_web_server: ping admin.mywebsite.com

must answer something like this:

PING admin.mywebsite.com (XXX.YYY.ZZZ.TTT) 56(84) bytes of data.
64 bytes from admin.mywebsite.com (XXX.YYY.ZZZ.TTT): icmp_seq=1 ttl=64 time=0.024 ms
64 bytes from admin.mywebsite.com (XXX.YYY.ZZZ.TTT): icmp_seq=2 ttl=64 time=0.029 ms
64 bytes from admin.mywebsite.com (XXX.YYY.ZZZ.TTT): icmp_seq=3 ttl=64 time=0.029 ms
64 bytes from admin.mywebsite.com (XXX.YYY.ZZZ.TTT): icmp_seq=4 ttl=64 time=0.029 ms

and opening URL http://admin.mywebsite.com/customadminpath in your favorite browser should display the Magento login form

Now everything is ready!. Let’s go and update our back-office URL

Step 5: Update Magento configuration to set the new back-office URL

So go in your current back-office and open the System > Configuration > General > Web > Unsecure URL tab: replace now in scope default the web unsecure URL by http://admin.mywebsite.com/. (Don’t forget to add the trailing / add the end of the URL).

Save config

Log out from the back-office

And open the http://admin.mywebsite.com/ URL. You should set the login form

Secure your back-office URL

Does your back-office is secured now?

It’s a shame but no:

  • Login form is still available from http://www.mywebsite.com/customadminpath
  • Everyone able to access to http://admin.mywebsite.com will be able to view the Magento login form.

Try it: open your old admin URL http://www.mywebsite.com/customadminpath/ you’ll still view the login form :(. The only thing we have done for now is to redirect people which provide valid login credentials to http://admin.mywebsite.com/customadminpath

Add the following rewrite rule in the Apache configuration file of the website virtualhost /etc/apache2/sites-available/magento.conf will redirect each user who try to access to admin from http://www.mywebsite.com/customadminpath/ to the admin domain name http://admin.mywebsite.com/:

<Virtualhost XXX.YYY.ZZZ.TTT:80>
      ServerName www.mywebsite.com
      DocumentRoot /a/path
      # redirect users to admin domain name if they try to access for login from website
      <IfModule mod_rewrite.c>
                RewriteEngine On
                RewriteCond %{HTTP_HOST} www.mywebsite.com [NC]
                # replace customadminpath by your own admin query string
                RewriteCond %{REQUEST_URI} ^.*/customadminpath/.*$
                RewriteRule ^(.*)$ http://admin.mywebsite.com/ [R=302,L]
      </IfModule>
      <Directory /a/path>
            # your magento configuration here
      </Directory>
</VirtualHost>

After an Apache restart, your login form is only available from http://admin.mywebsite.com

This is not the object of this post, but many things can be done to improve the ACL of your back-office. For example:

Is there an interest to use a custom domain name if you use the default behavior? I mean yes, and quickly.

Is there an interest to use a custom domain name if you already use something different than admin as suffix to access to your back-office? I mean yes. For sure, it’s quite more difficult to find it, but security issues have shown that it’s easily to find these “hidden” back-offices: Security through obscurity is not security. it’s just security for some times.

Patch against the Magento’s SUPEE-6482 issue

Hello everyone,

I know this is the holidays and you have probably only sun in mind, but security issues can’t wait: this morning Magento have published a new patch against SUPEE-6482 issue which include two issues related to APIs and two cross-site scripting risks.

Continue reading “Patch against the Magento’s SUPEE-6482 issue”

Are you still vulnerable after applying a Magento security patch?

Screenshot of the popin displayed in your back-office which notify about security patches

I salute Magento and all its partners for the notifications about security issues found.
Magento notify you in the back-office with some notifications.

These patchs are all available from the Magento download page and are distributed under a .sh file. You have just to run mypatchfile.sh and that’s it, you are secured!?

NO! Continue reading “Are you still vulnerable after applying a Magento security patch?”

High traffic websites under Magento: the Teleshopping example

TĂ©lĂ©shopping, one of the most older Magento project in France. With 41Meuros, website represents a tier of the turnover. Let’s see which technical choices has been made to provide a high performance website

Hello Gilles, maybe everyone doesn’t know you yet, could you please introduce yourself?

I’m in charge of the production center at Teleshopping. I am in charge of the operation, administration and system architectures for ERP and websites and for its subsidiaries (Euroshopping, Place des tendances and partly Direct Optic).

Two of your websites, Teleshopping and Euroshopping, are Magento-developed projects. Could you please tell us more about them?

Sure, Teleshopping’s website is among the first french Magento-developed websites, deployed in April 2009, and regularly updated since. There are approximately 1M unique visitors per month.

It allows its users to order products they have seen during the TF1 TV show. Ordering products from the catalog is done through another website.

Euroshopping’s website was deployed a little later, and there are about 100 000 unique visitors per month. It allows people to order products they have seen during TV shows on different TNT channels or on the cable.

Could you describe the general architecture within these two websites?

For Teleshopping, we have 10 front-end servers available for visitors, and one more for the back-office access

Proxy cache varnish is ahead each one of the servers. This may not be the best solution, but it allows us to regulate the number of front-ends without changing the configuration or having to ask ourselves too many questions.

Concerning the application, the source code is installed on every front-end server, there’s no replication and deliveries are hand-made.

But we share the media and skin directories on an NFS resource.

We use a memcached server with 1 port to put data in cache, and another port to put sessions in cache; this way we can flush data without any impact on the user’s sessions.

Concerning the database, we use a MySQL server which is replicated on a secondary server. All accesses are done on the main server.

Last element, the CDN. Medias are served by a CDN, which allows us to relieve at the outside our front-ends, even during the business campaigns.

Source images are put on an NFS resource available on every front-end.

For Euroshopping it’s at the most the same, except there’s no varnish, the 4 servers available are more than enough to manage the load.

How often do you deploy new versions?

It’s an average, but we do about 1 delivery in the production environment per month. Sometimes we may have more deliveries than that.

Could you tell us about your last deployment?

Every developer has its own development environment on a virtualized server, which is strictly the same as the production one.

A testing environment is available to validate the package before it’s installed on a pre-production environment. This delivery is done by my team.

Once the project manager has tested and approuved this package, it is delivered in the production environment, my team still doing it.

You are sharing the front-ends server’s contents on a NAS. What content do you exactly share?

We share the media and skin directories on our NAS, a filer NetApp. This sharing system is almost as performing as the local disk access, and its vantage is that we do not have to duplicate media files.

What made you choose this setup?

This sharing process is almost as performing as the local disk access, and its vantage is that we do not have to duplicate media files.

NFS and PHP tuning allows to manage access to the shared files with different cache levels.

We can manage the stock volume without any outage.

Could you tell us about the main problems you encountered while you were setting up this model?

We didn’t have any particular problem, only some tuning was needed for the NFS:

  • We mount the NFS shared folder with the following options tcp, rw, bg, hard, suid, noatime, nodiratime, nointr, timeo=600, retrans=2, rsize=32768, wsize=32768, actimeo=30
  • We have increased the PHP realpath cache to have a size of 1M and a TTL of 1 day

What benefits do you get from the source sharing between the different front-ends on a NAS?

Source sharing is useful to deliver the source code only once, it is then available for all of the front-ends; we do not need a “master” server from who to replicate the files.

Presently, the websites’s sources don’t allow us to share the whole source code, partly because of the /var/reports and /var/logs directories. For the next versions if source code allows it, we intend to share the whole source code for every front-end server.

How to patch PROPERLY Magento Zend Framework XML-RPC security issue?

On July, 5th, 2012, an important security issue has been highlighted in Zend Framework, and so in Magento. This issue allows people to read almost any file on your webserver. A very dangerous issue, that’s why it must be patched quickly

Tell me, how can we patch it?

Oh nice, there is a patch available. I open it, and now, I have some red spots appearing on my body: they edited the embedded Zend Framework and Magento core sources…. Almost everybody agree that we do not edit the Magento sources files. Why do it there?

A common workaround about Magento overloading is the following one: use local to patch Magento and Zend Framework files. We’ll use this way to patch the XML-RPC issue instead of editing Magento sources files

The following script updatepath.sh init your Magento so it can patch this way. It works with the provided patch file for CE 1.5 to 1.7 Magento version

#!/bin/bash
##################################
# config
##################################
LOCAL_FOLDER="app/code/local";
RESPONSE_FILE="Zend/XmlRpc/Response.php";
RESPONSE="$LOCAL_FOLDER/$RESPONSE_FILE";
REQUEST_FILE="Zend/XmlRpc/Request.php";
REQUEST="$LOCAL_FOLDER/$REQUEST_FILE";
PATCH_FILE="CE_1.5.0.0-1.7.0.1.patch";
DESTINATION_PATCH_FILE="kyp_$PATCH_FILE";
###################################
# process
###################################
# check if patch file already exists
if [ ! -f $PATCH_FILE ]; then
    echo "Patch file $PATCH_FILE does not exists. Please download it at http://www.magentocommerce.com/blog/comments/important-security-update-zend-platform-vulnerability/";
    exit 2;
fi
# create local folder if not exists (eg: CE1.7 and related EE)
if [ ! -d $LOCAL_FOLDER ]; then
   echo "Init app/code/local folder";
   mkdir $LOCAL_FOLDER
fi
# create folder for Zend Framework Response file patch
if [ ! -d "$LOCAL_FOLDER/Zend/XmlRpc" ]; then
    echo "Creating Zend/XmlRpc local folder";
    mkdir -p "$LOCAL_FOLDER/Zend/XmlRpc";
fi
if [ -f $RESPONSE ]; then
    echo "File $RESPONSE already exists. Please append patch in";
    exit 1;
fi
echo "copying $RESPONSE_FILE in local folder";
cp lib/$RESPONSE_FILE $RESPONSE;

if [ -f $REQUEST ]; then
    echo "File $REQUEST already exists. Please append patch in";
    exit 1;
fi
echo "copying $REQUEST_FILE in local folder";
cp lib/$REQUEST_FILE $REQUEST;
# update patch file to replace lib by app/code/local
echo "Update patch file"
sed "s|lib/|app/code/local/|g" $PATCH_FILE > $DESTINATION_PATCH_FILE
echo "new patch file $DESTINATION_PATCH_FILE has been generated. You can now apply it with patch -p0 < $DESTINATION_PATCH_FILE"

This way, you are sure that your Magento will always be patched, even if you upgrade to a prior version than 1.7.0.2 CE (first release which embedded the patch)

The only way it won't work is if you load Response.php and Request.php files with a requirement to full path to lib folder, but this is not the Magento best practices

High availability in Magento farm: the session problem

Big Magento websites require sometimes to be able to respond to a high traffic: there are many websites with high load, and sometimes, we must propose a magento farm behind a load balancer to be able to respond to all visits. But in this case, we have a choice to do about the load balancing: how is dispatched the load between Magento webservers?

And this choice that we have to make will have an impact about how sessions are managed

Depending on how are configured load balancers, we need perhaps share session between Magento front-webservers

Impact of load balancers configuration on the session storage management

Load balancers are in front of our webservers to be able to manage our webserver load

There are two ways to share the load between each front in load balancer when a customer is visiting a website:

  • he is always sent to the same webserver
  • According to the load, he is sent to the less loaded webserver

This load balancer configuration choice has an impact on the session management:

in the first case, we are always redirect to the same webserver.. But in this case, if the load of this server change we’ll have an end-user usage not as well as expected. In the worst case, if this websever become unavailable we wouldn’t be able to access the website anymore and the consequence is, and so loose some sales…

In the other case, we have not these disagrements because load is detected on load balancers and we are redirect to the most available server; but in this case we have the problem to share our sessions between each front to be able to retrieve our personals informations.

To ensure that we have the highest availability for our website, we’ll choose the second option and will see what solutions we have to share sessions between front web-servers

Reminder on PHP sessions storages

By default, PHP uses a session storage based on files: every time you start a session a file will be written on the webserver with the session content. it’s nice, but it has the disavantage to depend on which webserver you requested the information. If we are redirected to another webserver, the session file does not exist, and so, you’ve lost our cart…. How can we solve that?

PHP allows to redefine our PHP session storage model and define how are they managed. Nice, we’ll see how it can help us in our webserver farm management and our session sharing problem

The possible ways to share sessions in a Magento farm

Latest Magento release (1.6.2 CE, and related enterprise one) embeds many sessions storages management:

  • Files, the PHP default’s one
  • Database
  • Memcached
  • Othes choices?

Which advantage(s) have each one?

Sharing Magento sessions in a Magento farm with database(s)

In this case, we remplace the native PHP session storage management by a database: all sessions are stored in our database(s) server(s).

This solution is quite nice because each of our front webservers must be able to read and write in database; so there is no problem to share session: visitor will be redirected initially to a front webserver, init it session on it and save it’s customer session in database. Next page he request, load balancer will perhaps redirect him to another front-webserver, but with it session id, he’ll retrieve session data from the database and so, keep the same informations. Nice

But the problem in this situation is that we add another load on database server. Each visitor will make read and write instructions on our database server, and so, according to our traffic, it could be a very huge load. Furthermore, even if we add a very good cache policy, if our database webserver go down, our website won’t be available anymore.

Magento database table where are stored the sessions data is based upon file system. So If our server go down, we’ll be able to restore our session data. If Magento database availability is critical, there is some solutions like MySQL cluster to ensure that MySQL is always available. So we are able to provide a maximum service and a model tolerant to failure. But this model has the big problem to provide a important load on the database and it could be interesting to check the others availables solutionss

Sharing Magento sessions in a Magento farm with Memcached

Memcached is a memory server.

It can be use to:

  • Share cache data
  • Share sessions

One of the main advantage of memcached is that it’s a memory server, and so, read and write instructions will be made faster than with a file system

But we have two disavantages to use a memcached to store sessions:

  • Data integrity: memory does not check write as it’s done in a file system: writing in memory is not as secure as writing in a file system. Our data can be compromised, and so, loose part of our data.
  • We have the same problem as in the database: memcached is not tolerant to failure and so you’ll loose everything if it goes down; memcached can be clustered for cache storage, but in case of session sharing, we must provide only one server URI. So if server which manage session storage hang up, there is any session service available…

So for now, memcached has the only advantage to be able to share our sessions faster; it is not tolerant to failure and cannot be clustered so this is another risk in our architecture

Sharing sessions using a network shared folder and file system PHP storage

To avoid data integrity problem, we could continue to use a session file system storage, but share them between each front through a shared folder: in this case, all sessions storages location will be known by each server, and so, we can have the ability to use our session on each webserver. Data are also checked on write operations by the file system, so it’s nice

But this model has the disavantage to impose a network load every time you access a session. According to our website load, this network additionnal load could be critical

Sharing Magento sessions with Zend server

Based upon the PHP session storage file model, Zend Server embeds a session clustering between each front webserver zend server instance: Every starting session is copied on each Zend Server. So every time someone request a page from our webserver, it’ll be able to access our session file. Nice

Furthermore, when some data are written in session, Zend Server knows which is the main session storage file, and so is able to write in it.

If a front webserver go down, another session copy is used as main session file, and so you have no disagreement

For now, Zend Server session clustering is the only way to garantee that you won’t have any go down of our website and it provides data integrity using file system storage write control. But one of the disavantage is you need a Zend Server on each Magento front-office, and it increases our webhosting cost

Conclusion about the high availability storage management

Sales, television advertising or simply very basic traffic can lead you to have a dedicated magento farm to be able to answer all visitors requests. In this case, you should take care of always be able to answer all requests, not only for your orders but also for your branding

For sure, you can configure load balancing to always redirect a customer to the same server. This is the easyest way to configure load management, but is not the most reliable model and can provide some disagremments to our clients with possible no webservers response.

In the other case, the only way to ensure that we’ll have a high availability in a Magento farm is to ensure that the load is dispatched on front-webservers depending on their load. This brings the problem to share session between each webserver, but for now, the only secure way is to use Zend Server to clustering session.This model provide us a secure way to share session, ensure acces and write control, and does not add additionnal critical point in our architecture

Furthermore, it seems that choice of storage management has no performance impact. This is a first test, and we don’t know how it has been managed, but in the case mentionned, it seems that session_storage has no or few influence upon the performance

how to solve Magento message “Your web server is configured incorrectly. As a result, configuration files with sensitive information are accessible from the outside. Please contact your hosting provider.”

If you have this message when you are logged in your back-office, it’s because there is a misconfiguration in your Magento host. There are multiple reasons to have this message, and multiple ways to fix it

Why do I have this message displayed?

Since 1.4.2 version, back-office check from back-office if file app/etc/local.xml can be read through a browser (If the response code is a Apache 200 response code; This control is made by a CURL request on your unsecure_base_url/app/etc/local.xml URI) It’s very important not to be able to read this file from a webbrowser, because it contains your database parameters, cache and session configuration.

All files and folders in app folder are protected by a .htaccess file which denies access from everyone since it browses your Magento directory tree starting from the app folder:

Order deny,allow
Deny from all

this directive is applied starting from .htaccess path and covers also subfolders, and so, local.xml file

Origins of the problem

.htaccess usage can be disturbed for three major reasons:

htaccess file doesn’t exist

For sure, if htaccess file does not exist, there is no restriction on who can read the local.xml file, and so, the security warning is displayed

htaccess files are not the access filename

By default in Apache configuration, the AccessFilename is set to .htaccess. It can be updated with the AccessFilename directive in webserver or virtual host configurations files.

So if value has been updated, .htaccess will not be read, and so ACL is not used

But if this is your study case, you should have more complex problems with your Magento 🙂

Cannot override the directories acccess control list

Apache configuration allows also to define which rules can be overrided in AccessFilename with AllowOverride directive

If you are a hosting provider, perhaps you don’t want that your clients can update in their AccessFilename some security directives. It can be done with the AllowOverride directive

Have a look at the official documentation to see the possible values for this directive

In this case, if AllowOverride directive is not well set, the .htaccess file is read, but the ACL defined is not used, and so, we can have access to your local.xml file

Because this directive is applied only to <Directory;> instruction, you must be able to edit the vhost configuration file to fix this issue. Ask your hosting provider if you cannot

Specifics rewriting rules

For one client, we encounter this case: we have updated some elements of the Magento directory tree and define some specific rewriting rules. local.xml file was not available, but CURL test receive a 200 error code because of a rewriting rule.

In this case, this is the test which is involved, not your security policy

Conclusion

Configuration is checked on the app/etc/local.xml file, but other sensibles informations can be fetch from your app directory

It’s a shame that everybody doesn’t take care of this security issue. Take a look at the google results, you’ll be surprised

If your configuration is well set, when you request the app/etc/local.xml file on your Magento, you should have the following error displayed

Unix permissions policies on Magento

Recently, Prestashop has been attacked by a worm: this worm uploaded on the server was able to update the content of a template; this template load many iframe which make you request some unexpected things. Many users have been infected. According to the first feedback, it seems that a good unix permissions policy on Prestashop folder could have stopped this infection.

Magento‘s hosted on unix servers seem to have the same problem: even if there is – for the moment – no problem like Prestashop’s one, most of the plateforms I saw have unix permissions policy problems, and so provide attack facilities. This is the reason why I wrote this article.

Unix permissions resume

First remember the basic of unix permissions: For files and folders, they define if:

  • You can read a file / folder
  • You can write or delete a file / write in this folder
  • You can execute this file / browse the folder

They are defined for three users groups:

  • owner of the resource
  • one group of user
  • other users which are neitherbowner, nor member of the group defined

With this combination of users groups and roles, we can set the most common access permissions on our magento. But which one is the most secured one?

Unix permissions and Magento deployments methods

Permissions set are closely linked to your deployment method: Do you:

  • Upgrade magento directly with Magento connect?
  • Use the installer setup process and deploy your data with magento’s installers?
  • Copy a database coming from a previous server and update the configuration?

In the following article I’ll take the option that you test your updates on a non production server, push your source code through FTP, svn, or other file mechanism, and push your database upgrades with magento installers. Then, I’ll explain you which updates you require to be able to use other delivery mechanism.

Unix permissions Magento requirements

Unix permissions for Web server user in Magento

The most important thing from the point of view of your server security is the permissions defined for the owner of the files: this user run a server, so accept connexions. We must control which services can be provide by this server.
In most of the case this user is the user which run the webserver.

Common rules to apply

First, we will check what is requested for the webserver user to be able to use normally Magento scripts: this user needs to be able to read all files (this is the only requirement to be able to use PHP script) and be able to browse the magento directory tree. That’s all. So your PHP scripts must not have more than 4 octal permission. For your directory tree, we will give to your account access to read and browse, so 5 octal permission.

This is the most common structure for all Magento’s files and folders. Now we will take a look at some special cases.

Folders which require to be writable

Take a look now at the var and media subfolders; webserver user will write there its own data:

  • in var subfolder, he will write: backup files, log files, perhaps cache file, session user files, index process lock files, etc.
  • in media subofolder, he will write thumbnails and media librairy

So these two subfolders require the write permission.

Executables scripts by Webserver user

The question is : does your webserver user require to be able to execute scripts?
Depending on your Magento version, only two or four files require to be executable:

  • Installer script (pear for 1.4.2 or lower,  mage for the earlier versions): all to install modules from magento connect, or to be able to update directly from magento connect your magento
  • scheduler entry point cron.sh
  • pear embedded
  • pecl embedded

In our deployment model, pear is not used from back-office: so we do not set executable permission for our webserver to our webserver user: mage / pear / pecl won’t be executable by this user.
If you want to run scheduled tasks with this user, you must set up executable on the cron.sh file. But you can also run scheduled tasks with another account and so remove also this permission on this file for this user.

Unix permissions for group in Magento

Which group content ?

With group user, we will define all the permissions for administratives tasks: deploy, upgrade, maintenance management, etc.
This allow us to be really independant of the webserver user permissions.
So the group choice depends on who run these tasks. Most common thing is to set up the group of the administrative user as group.

Be able to upgrade source code

To be able to upgrade source code, this group must be able to write in all magento folders, delete, read files.

Be able to manage var data

Unix permissions for all others users in Magento

If all others users are not the owner of the file nor part of the group which realize the administrative tasks, they should not be able to access Magento directory tree: so no permissions

Unix permissions for others deployment methods

Deployment method with Magento connect

No, do you really update your source code from magento connect? Hope I won’t be on your website when you’ll do an upgrade 🙂

But anyway, in this case because it’s the webserver user which run magento connect, you must:

  • Give read / write on all files and folder (packages potentially contain files which can go in every folder).
  • Give the ability to execute mage / pear / pecl

This is one of the reason I don’t recommand this method: all your source files are potentially writeable by webserver user, and so, can be editable like in Prestashop worm.

Initial setup starting with Magento install program

In this case, there’s no big difference with the way I explained before: the only difference is on the app/etc/ folder which must be writeable during installation process to allow creation and update of the local.xml file. Then, when installtion process will finish, you can remove the write access on app/etc and app/etc/local.xml file.

Conclusion

You can find here a summary of the policy we should apply on our Magento folder.

#!/bin/bash
# 
# edit the following variables according with your server configuration
#
ROOT_UID="0"
GROUPUSERNAME=your_group
WEBSERVERUSERNAME=httpd
#
#Check if run as root
#
if [ "$UID" -ne "$ROOT_UID" ] ; then
   echo "You must be root to do that!"
   exit 1
fi
#
# ok, let's go for setting up permissions
#
chown $WEBSERVERUSERNAME:$GROUPUSERNAME "./*" -R
find . -type f -exec chmod 0460 {} \;
find . -type d -exec chmod 0570 {} \;
find var -type f -exec chmod 0660 {} \;
find var -type d -exec chmod 0770 {} \;
find media -type f -exec chmod 0660 {} \;
find media -type d -exec chmod 0770 {} \;
# set up installer script for our admin account
if [ -f pear ]; then
    chmod 0570 pear;
else 
   if [ -f mage ]; then
     chmod 0570 mage;
   fi
fi
if [ -f cron.sh ]; then
   chmod 0570 cron.sh
fi