@thomaszbz opened this Issue on June 16th 2015

Disclaimer: I'm using the term "backend" for the GUI accessible to authentificated users in this issue.

As far as I can see, Piwik claims to be easily installable in a wwwroot by just dropping the piwik files there. As long as secret resources like the Piwik backend are secured e.g. via login: This is nice and nothing to be concerned about, at least in the first place. Many php applications do it this way, as for example TYPO3 CMS.

However, there is also a different approach which can be considered paranoid by some people: Why on earth should ressources made public if there is no need to do so? What, if there's a security issue in the backend authentification of Piwik at some time? What, if some misconfigured web server does not render PHP files and offers a download instead?

In the Piwik scenario, there's only two things that need to be made public:

  • a way to track the user (via piwik.php and piwik.js)
  • a way to opt out from user tracking (and maybe similar public actions)

The problem here is that, currently,

  • most ressources are accessible in the wwwroot, even if there is no need for it
  • anonymous users need to access the same ressource to access the opt-out route. If the backend login shall be secured e.g. by additional apache authentification, then the opt-out route is not accessible by anonymous users. In the end, the backend resources (index.php) currently need to be accessible by anonymous users.
  • I can't see a concept to avoid these issues

To harden piwik, I schematically suggest an improved directory structure (which is similar to what some sophisticated php-frameworks like symphony2 offer):

/
    /bootstrap.php //optional
    /src  //for all the php code of piwik core
    /vendors //for all the files which are installed via composer
    /resources //like python administration scripts
    /cache //still to be protected for BC
    / optional: add wwwroot symlinks for frontend/index.php, piwik.js and piwik.php here
    /wwwroot
        /piwik.js   //for user-tracking
        /piwik.php  //for user-tracking
        / optional: add symlink for frontend/index.php
        /frontend
            /index.php //for anonymous, e.g. opt-out
            /assets //static content like css, images, ...
        /backend
            /index.php
            /assets //static content like css, images, ...

Basically, this means that php code is not accessible via url, as it resides in /src which is not in /wwwroot. Plus, the backend can be protected easily via URL /backend/*.

Still, the new structure allows not to use /wwwroot as wwwroot as well as using the same URLs via optional symlinks. Basically, this means piwik can still be just dropped somewhere in a wwwroot as before, thereby having the old level of security.

Keep in mind that the suggested directory structure was just schematically. Of course, the naming should better fit to what Piwik already uses. Therefore requires further discussion.

Right now, I worked around the problem with a proxy php file for the opt-out (securing the route which is accessible by anomynous users) and then securing anything else with additional http-authentification (.htaccess). Workaround (in German): http://www.slicewise.net/php/piwik-absichern/

There's other use-cases as well like

  • ensuring https-access to the backend on the level of the webserver (e.g. apache)
  • making the backend accessible only by a chosen network/domain on the level of the webserver

Thereby, BC may not be broken as

  • not every user can configure /wwwroot as the wwwroot because cheap web hosting will not offer apache vhost configuration. Plus, website and Piwik installation might use the same vhost. 301ing users is not a sophisticated option (performance).
  • piwik.js and piwik.php might still have to be accessible via http (not be forced to use https).
  • changing URLs of piwik.js and piwik.php might result in big confusion for many users. Same applies for the opt-out URL and routing.

Most of BC can be done via the corresponding symlinks (or duplicate files). Even if users can't configure their vhost to use /wwwroot as the wwwroot, they still benefit from being able to secure their Piwik installation via .htaccess.

@mattab commented on June 16th 2015 Owner

Hi @thomaszbz

Our official standpoint on this is that it can be done at the webserver level and we recommend to do it at the web server level. For example the nginx-piwik project: https://github.com/perusio/piwik-nginx will configure hardened security and will only allow access to those few needed files. Unfortunately we won't change the directory structure in Piwik core (it is too much work), so please consider doing it at web server config.

(leaving the issue opened as our decision may change in the future)

@thomaszbz commented on June 16th 2015

Actually, I expected that you would close this issue instantly either for being duplicate or somehow stupid/paranoid ;)

Now, the point is:

  • I consider https://github.com/perusio/piwik-nginx as a reference webserver setup which was done by one of the users. It comes along with all the webserver configuration from which most is not even specific to Piwik.
  • Using nginx just as a reverse proxy is a real overhead in my use-case. Never would I do that just to do some hardening which apache can do by itself perfectly (apache 2.4, debian 8).
  • I was already configuring some browser caching with apache, plus opcode caching. That works nice and was easy to do with apache .htaccess or vhost configuration. Nothing I'd need nginx for.
  • I strongly support the idea to not run into dependencies of specific web servers. Still, some basic reference configuration (which should be specific to Piwik) would be nice. Maybe a .__htaccess which can be copied to .htaccess and therefore can be changed easily even when using git.

Concerning https://github.com/perusio/piwik-nginx I want to remark that it does not fit my needs anyways:

  • Rules depending on referrers does not really improve security (using fraud-referrers is very easy).
  • There is no backend protection at all
  • Rules for bat|git|ini|sh|svn[^.]*|txt|tpl|xml are a workaround for the current directory structure (it's all in the wwwroot). Same applies for things like the mentioned "Do not serve HTML files from the /tmp folder" (...seriously???).

Actually, piwik-nginx really strengthens my opinion that the directory structure needs to be improved (or at least worked around) to be configurable by any webserver.

I guess that the fact that Piwik uses the same index.php for backend and frontend (e.g. opt-out) makes it impossible to distinguish both of them easily in webserver configuration rules (unless you work with rules on obscure URLs which can change every update).

At least, you could have a look at my workaround:

@thomaszbz commented on June 16th 2015

That's the workaround described in http://www.slicewise.net/php/piwik-absichern/ :

<?php
//index_public.php for the opt-out public route
if ($_GET['module'] === 'CoreAdminHome' && $_GET['action'] === 'optOut') {
    require_once('index.php');
} else {
    echo 'Error: Route not allowed.';
}

.

# .htaccess
<Files "*">
    Order deny,allow
    Deny from all
    Allow from <your-server-ip> #needed for some scripts, even when run locally
    AuthUserFile /path/to/piwik.htpasswd
    AuthName Piwik-Password
    AuthType Basic
    require valid-user
    Satisfy any
</Files>

<Files ~ "^piwik\.(js|php)|robots\.txt|index_public\.php$">
    Allow from all
    Satisfy any
</Files>

Basically, what it does:

  • Protect all files in wwwroot via http authentification (including the backend index.php)
  • Allow access to piwik.php and piwik.js
  • Allow access to a proxy php file (index_public.php) which checks for an allowed route and then delegates to index.php

This is not very sophisticated because

  • The route could change at any time
  • There is no real concept for public routes (maybe there's more to come)
  • I'm not sure if I met the routing right in terms of security (would need further investigation on the routing concept of Piwik)
  • ... again, it's just a workaround for the limitations of the current directory structure

However: Using a seperate proxy file allowed me to easily apply web server configuration rules. Maybe this could be an option for you if you don't want to change the whole directory structure. I could also live with a bunch of symlinks in a wwwroot subfolder collecting all the files to be URL-accessible from the original directory structure.

Still, there would be no dependency to a web server (e.g. apache, nginx).

Please don't get me wrong: I don't want you to add additional http authentification. This specific .htaccess is just one of the use cases I described.

@mattab commented on June 17th 2015 Owner

@thomaszbz if somehow you manage to create a good apache configuration for hardened Piwik, it would be great if you could put this on Github in a repository piwik-apache or so. We would gladly tell users to check it out. it would be similar to piwik-nginx and often I thought we should have the same for Apache :+1:

@thomaszbz commented on June 17th 2015

As said: A good webserver configuration (no matter which webserver) is currently not possible, as long as the limitations in the Piwik file structure exist. That should also hold true for piwik-nginx repository.

@funkyfuture commented on August 4th 2017

some remarks from my experience deploying piwik with nginx.

i first went more or less accordingly to https://github.com/perusio/piwik-nginx which is quiet obviously bloated as a general advise.
eventually i ended up with something like this to restrict full access to our local network only:


location / {
    deny all;

    location = /index.php {
        # test if there's a request to the admin interface from outside
        # the local network, drops the request unless the optOut-option is targeted
        if ( $remote_addr != "1.2.3.4" ) { set $admin_test "x"; }
        if ( $query_string !~ "^module=CoreAdminHome&action=optOut(&.*)?" ) { set $admin_test "${admin_test}x"; }
        if ( $admin_test = "xx" ) { return 444; }

        allow all;
        include snippets/fastcgi-php.conf;
        fastcgi_pass unix:/run/php/php7.0-fpm.sock;
    }

    location = /piwik.php {
        allow all;
        include snippets/fastcgi-php.conf;
        fastcgi_pass unix:/run/php/php7.0-fpm.sock;
    }

    location = /piwik.js {
        allow all;
    }

    location ~* \.(css|gif|html|js|png|svg)$ {
        allow 1.2.3.4;
    }
}

my suggestion would be to move the opt-out functionality to the piwik.php or an extra php-file, e.g. optout.php. which would allow to remove the usage of the if directive (which is evil):

location / {
    deny all;
    allow 1.2.3.4;

    location = /index.php {
        include snippets/fastcgi-php.conf;
        fastcgi_pass unix:/run/php/php7.0-fpm.sock;
    }

    location ~ /(optout|piwik)\.php {
        allow all;
        include snippets/fastcgi-php.conf;
        fastcgi_pass unix:/run/php/php7.0-fpm.sock;
    }

    location /piwik.js {
        allow all;
}
Powered by GitHub Issue Mirror