Why is the entire backend served from the root vhost directory?

I’ve been using concrete-css as my website engine of choice since concrete5 saved me having to roll my own CMSs back in the day. But one security issue that I have turned a blind eye to all these years has just been brought back to my attention by a work colleague - that of serving the entire application from a publicly accessible root directory.

It is generally considered to be best-practice these days to locate directories not intended for public indexing into an isolated parent directory e.g. most of a system’s files are located in a root directory which also contains a public folder, which is home to the dispatcher or index file, along with the site’s static files or assets. This /public directory is where the vhost is served from. As far as I know, nearly all modern web systems are structured in this way these days, for security reasons.

Is there any particular reason why concrete-css continues to serve everything from the root directory? My colleague has reminded me that this facilitates RCE vulnerabilities, and can expose the content of files to the screen in plain text if php is ever misconfigured such that it displays the code instead of running it. For example, the contents of /html/application/config/database.php could then be read via a browser …oops!

As an experiment, I tried creating a /public directory and changing a few core paths in the bootstrap config file, but this soon became unmanageable when namespaces started to need reconfiguring. One of the main issues is that the application takes its structure/location from DIR_BASE, which in turn takes its structure/location from $_SERVER[‘SCRIPT_FILENAME’], so the location of the dispatcher call (index.php) is key to everything else working harmoniously.

I’m no expert on application structures and security, so am I missing something here? Is there a mechanism beyond the use of ‘C5_EXECUTE’ that negates the best-practice need for an isolated public directory?

Or failing that, can anyone please help by suggesting a robust .htaccess configuration that would go some way towards protecting the backend directories against RCE attacks and server misconfiguration issues?

I can’t speak on behalf of the Concrete team, but I’m pretty familiar with the whole structure (and comparing it to something like Laravel).

Your points about keeping code directories out of the parent directory are all valid, but there’s some practicalities about how Concrete is structured (and the fact it’s a CMS) that mean that it’s not that easy to achieve.

Many files that Concrete ships with, whether it’s a theme’s javascript and css files, icon images, etc, need to be publicly available, and those kinds of files are generally stored alongside related php files. Think about block folders for example, they will have their controller.php file, but also might have a view.css file in the same directory.

If all that code was outside of the document root, there would have to be some sort of ‘publish’ process, that copies all these kinds of files back out to a public folder. Considering the variety of files in the core has in it that might need to be public, that’s a real pain.

The same goes for add-ons in the packages folder, they often have files in them that need to be public.

So the pragmatic approach is to keep everything in the public document root, but be very strict that requests have to go through the main request path, and therefore other PHP files can’t be accessed directly.

This is done by:

  • Concrete itself having defined(‘C5_EXECUTE’) on any php file that isn’t a class
  • The PRB having automated checks on submitted packages that they also have this in place for all files.

On top of that, with the broader way that Concrete is structured, the majority of functionality is handled via classes, and plain PHP files tend to just be templates. So even without the C5_EXECUTE lines in place, most of the time the PHP files just can’t do anything meaningful.

So it’s a bit of a balancing act, but the use of the C5_EXECUTE does effectively negate concerns about random scripts being able to be accessed. And I’m pretty sure this has been shown to be a solid strategy - I can’t ever recall seeing a security issue/fix due to a core file being publicly accessible.

If your server has PHP misconfigured to return files as plain text, we’re talking a pretty big stuff-up, one that I don’t think Concrete should need to provide protection for. An .htaccess file isn’t going to protect you from such a misconfiguration either.

The best thing to review is this documentation:

There might be some extra things in there you might want to investigate.

1 Like

Thanks for taking the time to respond to my post, Ryan, and I get that you’re not part of the team …but I still appreciate your many contributions over the years.

With regards to a ‘publish’ process, assets in a known location are generally simple to identify by their file suffixes, and something like gulp makes light work of copying assets to a /public folder - it’s a very common scenario for devs, as I’m sure you know. I get that this would be an extra step to configure/automate following installation of a block, but it’s probably doable without too much fuss.

With regards to .htaccess not protecting against php misconfigurations, .htaccess functions at the apache level, not the php level, so I think it would still be effective. And further on this subject, you and I are very unlikely to suffer many php misconfiguration issues, but I’ll wager that this isn’t the case for all concrete-cms users.

I think you sum it all up well when you say that it’s a bit of a balancing act, and I’m well aware that few devs have the time to make such a major change to the project (certainly not me). It’s a shame though, because it’s a major diversion from what has become best-practice in many people’s eyes, and rightly or wrongly, it doesn’t look good to some when first perusing the project’s file-tree.

In conclusion, I wondered if I was missing anything, but it appears that I’m not. Thanks again for your response.

You could use a php composer install to separate some stuff outside of the web root. Personally I think a composer install creates more problems than it solves and should certainly only be used by those who are experts in composer.

1 Like

Agree with Mesuva and John, that sums it up well. Thanks!