Using .htaccess to restrict access

Thanks for the commented example. It should be noted that what you can do in the .htaccess is limited by the virtual host config (eg AllowOverride and Apache modules installed).

Are you sure this is tested? Looking at the rewrite rules, it looks like basic tracking is broken.

Yep, I’ve been using it on Piwik 1.5 - 1.6. It actually also works on Piwik 1.7 and 1.7.1 but I could not test if I, e.g., could activate what I commented out under “Comment by jawsmith: commented following out, as otherwise error by the world map widget (flash)”, which is why “tested with Piwik 1.6” and not with the 1.7.1. I wanted to test that because, if I remember it correctly, it has been planned to get rid of flash widgets altogether at some point - not sure if that has been done in 1.7.1 already.

The reason for the inability to test is the “Widgets not found” (301 Moved Permanently) issue I’m having since 1.7, which is not influenced by the presence of the above .htaccess file. A fresh test site installation I used to test that problem has never had that file.

What I am not able to test generally, is the “one-click update”, which I cannot use due to global restrictions of my free hosting provider. I always have to do the update via FTP.

It doesnt work for my site.

Exactly what I was looking for. Thank you guys you are awesome. The possibilities with .htaccess are big. Could anyone explain me how to do a 301 redirect’ because I cant get it work.

Hi, the 301 redirect is, as stated, a “sub-domain prevention AND www requirement” in the same rule. If one of those is not what you need, refer to the original rule in htaccess examples (security) - Joomla! Documentation, i.e. use one of the following:

########## Begin - Redirect non-www to www
RewriteCond %{HTTP_HOST} !^www\. [NC]
RewriteRule ^(.*)$ http://www.%{HTTP_HOST}/$1 [R=301,L]
## If the above throws an HTTP 500 error, swap [R=301,L] with [R,L]
########## End - Redirect non-www to www
 
########## Begin - Redirect www to non-www
## WARNING: Comment out the non-www to www rule if you choose to use this
# RewriteCond %{HTTP_HOST} ^www\.(.+)$ [NC]
# RewriteRule ^(.*)$ http://%1/$1 [R=301,L]
## If the above throws an HTTP 500 error, swap [R=301,L] with [R,L]
########## End - Redirect non-www to www

If you need to enforce HTTPS, refer to the “Force HTTPS for certain pages” rule in the file in htaccess examples (security) - Joomla! Documentation, i.e.:

########## Begin - Force HTTPS for certain pages
# Force the page foobar.html to run in HTTPS mode, no matter what Joomla! says.
# This is a sample redirection for foobar.html. Do note that you have to change
# www.example.com to reflect your own domain. Remember to escape the dots using
# \. in the left hand side of each rule. You need BOTH LINES PER URL for the rule
# to work.
RewriteCond %{SERVER_PORT} !^443$
## Alternatively, comment the above line and uncomment the following line:
# RewriteCond %{HTTPS} ^off$ [NC]
RewriteRule ^foobar\.html$ https://www.example.com/foobar.html [R=301,L]
## NOTE: If you get an HTTP 500 error, please swap [R=301,L] with [R,L]
# Add more rules below this line as required
########## End - Force HTTPS for certain pages

P.S.: The “Advanced server protection - paths and files” in the .htaccess file posted by me above could do with some minor simplification, as Piwik (unlike Joomla) does not use, nor require, SEO. I’ll post an update some time soon.

[quote=“Jezreel Ricafort”]
It doesnt work for my site.[/quote]

You need to find out which rule(s)/condition(s) (it may be several) break it for you, and disable them (see also comment lines for possible alternatives). To do that, start disabling (i.e. commenting out) the rules/conditions successively, and testing, until the problem disappears. Then, start successively re-enabling the ones before the problematic one, and testing, until you either re-enabled them all, or found other rule(s)/condition(s) causing problems.

For information on meaning of the RewriteRule flags (F, L, R, NC, OR, etc.), see RewriteRule Flags - Apache HTTP Server Version 2.2.

Hi!

I have difficulties with PIWIK which may be related to hardening its security by htaccess files. The effect her is: My PIWIK is now running, but I only can see visitors in the widget “visitors in real time”. All other widgets do not show up any data.

I am new to PIWIK. But I am experienced in running 5 Joomla sites on my Managed Hosting Webspace at DomainFactory Munich, Germany. While making these installations as sure as I can, I have uses htaccess files as well as Quotas. By this each Joomla installation is separated from the others. In case, one gets hacked, the others cannot be affected also!

Further I am using one htaccess in the quota above the root directory. This “main htaccess” does keep out all requests and access, which is definitively not necessary for regular use of Joomla etc. And then I have a second htaccess in each website root, which can do some things which are specific to that domain of that website like having access only via https or changing from www URL to non-www and so on.

The developement of my htaccess files was original based on the Joomla proposals. But soon I had to learn via the Forum of DomainFactory, that many rules in the Joomla proposals had wrong syntax or were not valid at all or they were duplicates. In the Forum, they helped me to get these htaccess right. And in my special constructions, we had to insert a command, so that the rules of the main htaccess would inherit and would not be overwritten by the htaccess in the root of the websites.

My difficulty in this case with PIWIK is, that I cannot define, what PIWIK does need for functioning well and which procedures I could prevent by rules in the htaccess. My PIWIK is now running, but I only can see visitors in the widget “visitors in real time”. All other widgets do not show up any data.

I will show you my htaccess files now. The first is the main htaccess which does nearly all jobs:



##### MAIN  HTACCESS (Top quota) ####
#### basics ####
RewriteEngine On
Options +FollowSymLinks
ServerSignature Off
Options All -Indexes
AddDefaultCharset utf-8

### Limit access to valid HTTP requests only ###
RewriteCond %{THE_REQUEST} !^[A-Z]{3,9}\ .+\ HTTP/(0\.9|1\.0|1\.1) [NC]
RewriteRule .* - [F,L]

### Limit requests methods  #####
RewriteCond %{REQUEST_METHOD} !^(GET|POST) [NC,OR]
RewriteCond %{THE_REQUEST} (\\r|\\n|%0A|%0D) [NC,OR]
RewriteCond %{HTTP_REFERER} (<|>|'|%0A|%0D|%27|%3C|%3E|%00) [NC,OR]
RewriteCond %{HTTP_COOKIE} (<|>|'|%0A|%0D|%27|%3C|%3E|%00) [NC,OR]
RewriteCond %{REQUEST_URI} ('|%0A|%0D|%27|%3C|%3E|%00) [NC,OR]
RewriteCond %{REQUEST_URI} ([,;:<>]|">|"<|\\\.\.\\) [NC,OR]
RewriteCond %{REQUEST_URI} (=|@|\[|\]|\^|'|\{|\}|~) [NC]
RewriteRule .* - [F,L]

### Block some user agents ####
RewriteCond %{HTTP_USER_AGENT} (winhttp|HTTrack|clshttp|archiver|loader|email|harvest|extract|grab|miner) [NC,OR]
RewriteCond %{HTTP_USER_AGENT} (java|libwww-perl|curl|wget|python|nikto|scan) [NC,OR]
RewriteCond %{HTTP_USER_AGENT} (<|>|'|%0A|%0D|%27|%3C|%3E|%00) [NC]
RewriteRule .* - [F,L]

### Block some query exploits and SQL #####
RewriteCond %{QUERY_STRING} (ftps?|https?):// [NC,OR]
RewriteCond %{QUERY_STRING} (<|%3C).*iframe.*(>|%3E) [NC,OR]
RewriteCond %{QUERY_STRING} (<|%3C).*script.*(>|%3E) [NC,OR]
RewriteCond %{QUERY_STRING} (%0|127\.0) [NC,OR]
RewriteCond %{QUERY_STRING} (\*|;|<|>|'|"|\)|\(|\?|%%|&%%|&") [OR]
RewriteCond %{QUERY_STRING} (%0A|%0D|%22|%27|%3C|%3E|%00) [NC,OR]
RewriteCond %{QUERY_STRING} (globals|encode|localhost|loopback|127\.0\.0\.1) [NC,OR]
RewriteCond %{QUERY_STRING} \b(union|insert|cast|set|declare|drop|md5|benchmark)\b [NC,OR]
RewriteCond %{QUERY_STRING} (\.\./|/\.\.|\./\.) [OR]
RewriteCond %{QUERY_STRING} base64_encode[^(]*\([^)]*\) [OR]
RewriteCond %{QUERY_STRING} (GLOBALS|_REQUEST)(=|\[|%[0-9A-Z]{0,2}) [NC]
RewriteRule .* - [F,L]

### Block some file injections ####
RewriteCond %{REQUEST_METHOD} GET
RewriteCond %{QUERY_STRING} [a-zA-Z0-9_]=(\.\.//?)+ [NC,OR]
RewriteCond %{QUERY_STRING} [a-zA-Z0-9_]=/([a-z0-9_.]//?)+ [NC]
RewriteRule .* - [F,L]

### Disallow PHP fingerprinting attacks  ###
RewriteCond %{QUERY_STRING} ^.*=PHP[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12} [NC]
RewriteRule .* - [F,L]

### don't allow access to htaccess itself ###
<Files .htaccess>
 Order Deny,Allow
 Deny from all
</Files>


In a directory beneath this, I have set up another quota, so that never someone can get access to the directory above. In this lower directory, I have put PIWIK. In the root of PIWIK I am using this htaccess file:


#### SUB HTACCESS (lower quota) ###


### basics ###
RewriteEngine On
RewriteBase /
RewriteOptions inherit

#### optional non www to www URL  ###
# RewriteCond %{HTTP_HOST} ^meinesite\.de$ [NC]
# RewriteRule ^(.*)$ http://www.meinesite.de/$1 [R=301,L]

#### optional www to non www URL  ###
# RewriteCond %{HTTP_HOST} ^www\.meinesite\.de$ [NC]
# RewriteRule ^(.*)$ http://meinesite.de/$1 [R=301,L]

### prevent redirect loops ###
RewriteCond %{ENV:REDIRECT_STATUS} !^$
RewriteRule .* - [L]

### only access via https connections #####
RewriteCond %{SERVER_PORT} !=443
RewriteRule ^ https://www.meinesite.de%{REQUEST_URI} [NS,R,L]

### Allow Piwik API files
RewriteRule ^piwik/(index\.php|piwik\.(php|js))$ - [L]
RewriteRule ^piwik/js/(index\.php|piwik\.js)$ - [L]

### Disallow front-end access for certain Piwik system directories
### (Note: "js" directory deliberately not disallowed, as contains scripts accessible by browser)
RewriteRule ^piwik/(config|core|lang|misc|tests|tmp)/ - [F]

### Allow limited access for certain Piwik system directories with client-accessible content
RewriteRule ^piwik/(libs|plugins|themes)/([^/]+/)*([^/.]+\.)+(jp(e?g|2)?|png|gif|bmp|css|js|swf|html?|pdf|svg|ico)$ - [L]
RewriteRule ^piwik/(libs|plugins|themes)/ - [F]

### protect htaccess
<Files .htaccess>
 Order Deny,Allow
 Deny from all
</Files>


Is there anyone who can help me with this?

Kind regards Clemens

If you remove the piwik related parts in the htaccess, does it work fine ?

Hi Matt!
In the meantime, I have made several changes and suddenly, PIWIK showed up the data, which I have missed. I am sorry, that I cannot contribute by describing any real reason, why it did not work before and now it does.

But my contribution is the posting of the two htaccess above and I hope, they are a good hint for security aware people. And yes, my PIWIK is up and running with all the htaccess rules, I have posted above.
A great gain in security is achieved by having the most important security giving rules in the “main” htaccess which is out of the quota of the PIWIK installation. There has been an exploit in Wordpress some months ago, where the hackers could get access to the htaccess and modified it, so that code from their server was inserted automatically in the wordpress site. With my construction of separate htaccess within a different quota, this attack (and all similar) is simply not possible.

I have another security related question related to htaccess and https:
We want a secure data transmission from and to PIWIK. I am wondering, why in the first line of the tracking script, it is allowed to access PIWIK via http as well as https:


var pkBaseURL = (("https:" == document.location.protocol) ? "https://meine-piwik-analyticseite.de/" : "http://meine-piwik-analyticseite.de/");

and this while I have defined in htaccess, that any http-connection is allowed only in https.

And at the end of the tracking script, we have the noscript department with:


<noscript><p><img src="http://meine-piwik-analyticseite.de/piwik.php?idsite=1" style="border:0" alt="" /></p></noscript>

with the same difference.

Kind regards
Clemens

Hi!
First, I have to admit, that I have made a mistake in the first (main) htaccess, I had posted above:

In the section

Block some query exploits and SQL

the rule

RewriteCond %{QUERY_STRING} (globals|encode|localhost|loopback|127.0.0.1) [NC,OR]

has to be changed to

RewriteCond %{QUERY_STRING} (encode|localhost|loopback|127.0.0.1) [NC,OR]

as it seems, that “globals” is needed by PIWIK.

Second, I want to let you know about my experiences here with security and SSL protocol:
1.) My ISP offers to connect via HTTPS or FTPS. But there is no valid certificate for that SSL connection, until I would buy one.
2.) I will not buy a certificate, because past experience shows, how easy certificates can be falsified or be stolen (Verizon, Diginotar etc.)
3.) I see, that I want to profit from the security of encrypted data transfer of a HTTPS connection but do not need the validation of identity by a certificate.
3.) My ISP offers a “general certificate”. But actual webbrowsers will show a warning concerning an invalid certificate and asks, whether to accept this.
4.) I have been in sorrow, how PIWIK would handle with this circumstance and in conjunction with my htaccess solutions.

Additional to the rule in the second htaccess file, I have added to config.ini.php of PIWIK the two lines
[General]
force_ssl = 1

I have not experienced problems with this. But I cannot be “listen to the tracking script” and so I am not absolutely sure, whether there will be HTTPS data transfer.

As a consequence, my question above tends to be answered, but I am still not sure, whether the script really will transmit via HTTPS. Can anybody confirm please?

Kind regards
Clemens

Sorry to say… its just now that I experience, that my last change in th SSL settings did break some things. The URLs of visited sites were not collected anymore and also no search keywords etc.

The reason: At least, when in config.ini.php of PIWIK the SSL-connection is mandatory activated, then in htaccess the rule, to enforce HTTPS connection has to be commented out or may not be used.

Since I have removed this rule, everything works very well!

Kind regards
Clemens

For those who are on shared hostings with apache 2.4. Useful if you have in your DNS records more domains associated to piwik installation path. This allow connection to the site/admin/API/cron if piwik is loaded under specific domain “allowed.com”, for all other domains are allowed just load piwik.js (cache for one week) and piwik.php (cache disabled).


<IfModule mod_expires.c>
ExpiresActive on
ExpiresByType image/jpg "access plus 60 days"
ExpiresByType image/png "access plus 60 days"
ExpiresByType image/gif "access plus 60 days"
ExpiresByType image/jpeg "access plus 60 days"
ExpiresByType text/css "access plus 1 days"
ExpiresByType image/x-icon "access plus 1 month"
ExpiresByType application/pdf "access plus 1 month"
ExpiresByType audio/x-wav "access plus 1 month"
ExpiresByType audio/mpeg "access plus 1 month"
ExpiresByType video/mpeg "access plus 1 month"
ExpiresByType video/mp4 "access plus 1 month"
ExpiresByType video/quicktime "access plus 1 month"
ExpiresByType video/x-ms-wmv "access plus 1 month"
ExpiresByType application/x-shockwave-flash "access 1 month"
ExpiresByType text/javascript "access plus 1 week"
ExpiresByType application/x-javascript "access plus 1 week"
ExpiresByType application/javascript "access plus 1 week"
</IfModule>


# Very useful if you run piwik on multiple domains like:
#piwik.domain.com/piwik.php - just for tracking purposes
#piwik.allowed.com/ - for tracking and administration purposes

<Files piwik.js>
SetEnvIfNoCase ^Accept.Encoding$ ^(.*)$ fix_accept_encoding=$1
Header set Accept-Encoding %{fix_accept_encoding}e env=fix_accept_encoding
Require all granted
</Files>
<Files piwik.php>
Header set cache-control: "no-cache, public, must-revalidate"
Header set Expires "Fri, 01 Jan 2010 00:00:00 GMT"
Require all granted
</Files>
<If "(%{HTTP_HOST} -strcmatch '*allowed.com*')">
Require all granted
</If>
Require all denied

Do you know how to enter this .htaccess code for Prestashop users?

I tried entering in and it crushed my whole website - so needed to delete.

Thanks a lot

I write .htaccess to restrict spam website to my site, htaccess is usefull and great. Thanks.

Oh, thank you very much.
No idea i can do this.

I’m using the opt-out site and need that page to be excluded from protection.

The path is: index.php?module=CoreAdminHome&action=optOut&language=de

This works but excludes the whole index.php from protection:

<Files ~ “^piwik.(js|php)|robots.txt|index.php$”>

I only want the opt-out page to be excluded but this doesn’t work:

<Files ~ “^piwik.(js|php)|robots.txt|index.php?module=CoreAdminHome&action=optOut&language=de$”>

What can I do?

I´ve looked for quite a long time, but unfortunately didn´t find a solution for the problem with the OptOut (requested ba query string of the index.php). In my opinion it´s an issue or improper programming … why can´t the Piwik team just offer a solution for that?

Best regards, John

[quote=John_Delay]
I´ve looked for quite a long time, but unfortunately didn´t find a solution for the problem with the OptOut (requested ba query string of the index.php). In my opinion it´s an issue or improper programming … why can´t the Piwik team just offer a solution for that?

Best regards, John[/quote]

Hi xrev, John_Delay,

this forum topic has become a community effort, not one majorly by the Piwik team. (Thanks to the Piwik team for the great work, btw.!)

Although I don’t know why you would like to block general access to “index.php”, as that would break access to the user interface of Piwik, my guess is that you are missing the concept of “regular expressions” in an Apache htaccess file. A quick googling for “apache htaccess regular expressions” brings up a good description of them in http://www.webmasterworld.com/forum92/4332.htm (or Apache mod_rewrite Introduction - Apache HTTP Server Version 2.4 if you use “mod_rewrite”, which you don’t seem to).

I.e., your “?”, etc., are interpreted as regular expressions. If you need them to be interpreted literally, you would need to “escape” them by placing the “escape” character “\” (backslash) before each regular expression character.

Hope this helps.

This is an update to the .htaccess example file originally posted by me in 301 Moved Permanently above. I’m deliberately positing the update in a new post, instead of just updating the original one (where I’m going to add a reference to the new post), so that file comparison (copy and paste in the tool of your choice) can be used to easily see the changes introduced.

I did NOT incorporate any other .htaccess rule proposals below my original post – I’ll leave it to the user, if desired. Partly due to my incompetence.

The goal of this update was simplification (which I promised earlier) of the “Advanced server protection – paths and files” part at the end of the original .htaccess file, as Piwik (unlike Joomla) does not use, nor require, SEO. While on it, I also found two bugs, which might have been responsible for some of the “it doesn’t work for me” comments after my original post. I apologize for the inconvenience caused:

  1. Lines 108 and 110 of the original post: A backslash between “GLOBALS(=|” and “_REQUEST(=|”, and the following “[“ got somehow lost on the file submission. (I guess it was filtered out by the post submission system - see comment after the code below.) I’ll compare the posted end result to my local copy this time, to make sure that nothing gets lost this time.

  2. Line 154 of the original post: The “L” flag was missing in “[R=301,L]”. This is a real bug of mine – the “L” flag is needed, even though the comment above that line (removed in the new version) claims the opposite. The bug didn’t show itself on my setup until I started adding the optimizations I did at the end of the file.

While at it, I’m also reviewing and updating the post comments before and after the code. So, here comes the complete rewrite of the original post:

Here is another example of securing your Piwik installation, based on Joomla .htaccess example under htaccess examples (security) - Joomla! Documentation, modified and adapted to Piwik. Please refer to that for additional information, if needed. The file is being used on a free shared web hoster (i.e. php.ini, etc., is not modifiable).

It does not use user or IP authentication (which could be done additionally as shown in posts above, if desired).

The assumed Piwik installation address is www.test.example.com/piwik/, with the www.test.example.com domain used exclusively for the only one Piwik installation, and the below .htaccess file placed into its main directory (i.e. above the /piwik/ directory). Although, I suggest using a different directory name and use of the “/js” tracking subdirectory of Piwik (instead of “piwik.js”) as described in “README” in the “js/” directory of your Piwik installation, to not have the “piwik” string anywhere in the URL. Because privacy tools, such as some AdblockPlus filter lists, have started blocking content from URLs containing that string anywhere in the URL.

###############################################################################
## .htaccess example implementation, last tested with Piwik 1.11.1
##
## Based on version 2.5 (proposed) of May 16th, 2011 (proposed 2.5.5 wiki doc
## history verstion by G1smd of May 17th, 2011) Joomla .haccess file
## example under http://docs.joomla.org/Htaccess_examples_%28security%29
##
###############################################################################

########## Begin - RewriteEngine enabled
RewriteEngine On
########## End - RewriteEngine enabled

########## Begin - RewriteBase
# Uncomment following line if your webserver's URL
# is not directly related to physical file paths.
# Update Your Joomla! Directory (just / for root)

#RewriteBase /
########## End - RewriteBase

########## Begin - No directory listings
## Note: +FollowSymlinks may cause problems and you might have to remove it
IndexIgnore *
Options +FollowSymLinks All -Indexes
########## End - No directory listings

########## Begin - File execution order, by Komra.de
DirectoryIndex index.php index.html
########## End - File execution order

########## Begin - ETag Optimization
## This rule will create an ETag for files based only on the modification
## timestamp and their size. This works wonders if you are using rsync'ed
## servers, where the inode number of identical files differs.
## Note: It may cause problems on your server and you may need to remove it
FileETag MTime Size
########## End - ETag Optimization



#####################################################
# Beginning of additional settings by jawsmith (from the
# "htaccess.txt" provided with Joomla, and Joomla
# security forums)
#####################################################
# Code taken from "Other useful settings" of http://docs.joomla.org/Htaccess_examples_(security)
ServerSignature Off

# Disable all methods except GET and POST, as only those are needed
# (Note: TRACE does not seem to be possible to disable in .htaccess, only in server config by the host)
RewriteCond %{REQUEST_METHOD} !^(GET|POST) [NC]
# Return 405 Method Not Allowed
RewriteRule .* - [R=405,L]

RewriteCond %{THE_REQUEST} (\\r|\\n|%0A|%0D) [NC,OR]
RewriteCond %{HTTP_REFERER} (<|>|’|%0A|%0D|%27|%3C|%3E|%00) [NC,OR]
RewriteCond %{HTTP_COOKIE} (<|>|’|%0A|%0D|%27|%3C|%3E|%00) [NC,OR]
RewriteCond %{REQUEST_URI} ^/(,|;|:|<|>|”>|”<|/|\\\.\.\\).{0,9999} [NC,OR]

# Note: User agents blocking not taken over, as agent names could easily be changed, and e.g. Nikto is used by me as well on http://www.hackertarget.com/website-scan

#Block mySQL injects
RewriteCond %{QUERY_STRING} (;|<|>|’|”|\)|%0A|%0D|%22|%27|%3C|%3E|%00).*(/\*|union|select|insert|cast|set|declare|drop|update|md5|benchmark) [NC,OR]
RewriteCond %{QUERY_STRING} \.\./\.\. [OR]
RewriteCond %{QUERY_STRING} (localhost|loopback|127\.0\.0\.1) [NC,OR]
# Comment by jawsmith: commented following out, as otherwise error by the world map widget (flash)
#RewriteCond %{QUERY_STRING} \.[a-z0-9] [NC,OR]
RewriteCond %{QUERY_STRING} (<|>|’|%0A|%0D|%27|%3C|%3E|%00) [NC]
# Note: The final RewriteCond must NOT use the [OR] flag.

# Return 403 Forbidden
RewriteRule .* - [F]

# Note: Protecting .htaccess and other files explicitly is not necessary - they will be implicitly protected by the access lockdown at the end of the file
#####################################################
# End of additional settings by jawsmith
#####################################################



########## Begin - Rewrite rules to block out some common exploits
## If you experience problems on your site block out the operations listed below
## This attempts to block the most common type of exploit `attempts` to Joomla!
#
# If the request query string contains /proc/self/environ (by SigSiu.net)
RewriteCond %{QUERY_STRING} proc/self/environ [OR]
# Block out any script trying to set a mosConfig value through the URL
# (these attacks wouldn't work w/out Joomla! 1.5's Legacy Mode plugin)
RewriteCond %{QUERY_STRING} mosConfig_[a-zA-Z_]{1,21}(=|\%3D) [OR]
# Block out any script trying to base64_encode or base64_decode data within the URL
RewriteCond %{QUERY_STRING} base64_(en|de)code[^(]*\([^)]*\) [OR]
## IMPORTANT: If the above line throws an HTTP 500 error, replace it with these 2 lines:
# RewriteCond %{QUERY_STRING} base64_encode\(.*\) [OR]
# RewriteCond %{QUERY_STRING} base64_decode\(.*\) [OR]
# Block out any script that includes a <script> tag in URL
RewriteCond %{QUERY_STRING} (<|%3C)([^s]*s)+cript.*(>|%3E) [NC,OR]
# Block out any script trying to set a PHP GLOBALS variable via URL
RewriteCond %{QUERY_STRING} GLOBALS(=|\[|\%[0-9A-Z]{0,2}) [OR]
# Block out any script trying to modify a _REQUEST variable via URL
RewriteCond %{QUERY_STRING} _REQUEST(=|\[|\%[0-9A-Z]{0,2})
# Return 403 Forbidden
RewriteRule .* - [F]
#
########## End - Rewrite rules to block out some common exploits

########## Begin - File injection protection, by SigSiu.net
RewriteCond %{REQUEST_METHOD} GET
RewriteCond %{QUERY_STRING} [a-zA-Z0-9_]=http:// [OR]
RewriteCond %{QUERY_STRING} [a-zA-Z0-9_]=(\.\.//?)+ [OR]
RewriteCond %{QUERY_STRING} [a-zA-Z0-9_]=/([a-z0-9_.]//?)+ [NC]
RewriteRule .* - [F]
########## End - File injection protection

########## Begin - Advanced server protection - query strings, referrer and config
# Advanced server protection, version 3.2 - May 2011
# by Nicholas K. Dionysopoulos

## Disallow PHP Easter Eggs (can be used in fingerprinting attacks to determine
## your PHP version). See http://www.0php.com/php_easter_egg.php and
## http://osvdb.org/12184 for more information
RewriteCond %{QUERY_STRING} \=PHP[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12} [NC]
RewriteRule .* - [F]

## SQLi first line of defense, thanks to Radek Suski (SigSiu.net) @
## http://www.sigsiu.net/presentations/fortifying_your_joomla_website.html
## May cause problems on legitimate requests
RewriteCond %{QUERY_STRING} concat[^\(]*\( [NC,OR]
RewriteCond %{QUERY_STRING} union([^s]*s)+elect [NC,OR]
RewriteCond %{QUERY_STRING} union([^a]*a)+ll([^s]*s)+elect [NC]
RewriteRule .* - [F]

########## End - Advanced server protection - query strings, referrer and config

########################################################################
# Added by jawsmith: sub-domain prevention and www requirement (redirect with code 301 ("moved permanently")
# in the same rule
# Notes: 1. If you want to do it separately, or use https, refer to Joomla reference htaccess implementation
#        2. This needs to be done before the below file protection exceptions,
#           so that the redirect occurs before the exceptions are accessed.
#        3. Replace test.example.com with your own domain
########################################################################
RewriteCond %{HTTP_HOST} !^www\.test\.example\.com$
RewriteRule ^(.*)$ http://www.test.example.com/$1 [R=301,L]

########## Begin - Advanced server protection rules exceptions ####
##
## These are sample exceptions to the Advanced Server Protection 3.1
## rule set further down this file.
##
## Allow robots exclusion file
RewriteRule ^robots\.txt$ - [L]

########## End - Advanced server protection rules exceptions ####

########## Begin - Advanced server protection - paths and files
## Allow Piwik API files or plain directories
RewriteRule ^piwik(/(index\.php|piwik\.(php|js))?)?$ - [L]
RewriteRule ^piwik/js(/(index\.php|piwik\.js)?)?$ - [L]

## Allow limited access for certain Piwik system directories with client-accessible content
RewriteRule ^piwik/(libs|plugins|themes)/([^/]+/)*([^/.]+\.)+(jp(e?g|2)?|png|gif|bmp|css|js|swf|html?|pdf|svg|ico)$ - [L]

## Disallow access to all other (works, as only resources explicitly allowed above are accessed, no SEO pseudo directories)
RewriteRule .* - [F]

########## End - Advanced server protection - paths and files

[b]CAUTION: As described in the bug number 1 before the code above, a backslash between “GLOBALS(=|” and “_REQUEST(=|”, and the following “[“ gets lost on the file submission on lines 99 and 101 of the above code. I.e., correct as follows, by replacing the “BACKSLASH” string with a “\”:

  • Line 99: RewriteCond %{QUERY_STRING} GLOBALS(=|BACKSLASH[|%[0-9A-Z]{0,2}) [OR]
  • Line 101: RewriteCond %{QUERY_STRING} _REQUEST(=|BACKSLASH[|%[0-9A-Z]{0,2})[/b]

What I am not able to test, is the “one-click update”, which I cannot use due to global restrictions of my free shared hosting provider. (The server is not allowed to fetch anything from anywhere, among other things.) I always have to do the update via FTP. (By just creating a “diff” of a new Piwik version and uploading only that.)

If the above .htaccess example doesn’t work for you after you updated it for your needs as described in its comments (e.g. the Piwik installation URL), you will need to find out which rule(s)/condition(s) (it may be several) break it for you, and disable them (see also comment lines for possible alternatives). To do that, start disabling (i.e. commenting out) the rules/conditions successively, and testing, until the problem disappears. Then, start successively re-enabling the ones before the problematic one, and testing, until you either re-enable them all, or find other rule(s)/condition(s) causing problems. For information on meaning of the RewriteRule flags (F, L, R, NC, OR, etc.), see RewriteRule Flags - Apache HTTP Server Version 2.2.

Additional hint: As with any other web application, unless you use https AND your server TLS is super up-to-date AND your client is up-to-date and secure, try to log-in to your Piwik installation with administrator rights as little as possible. Simply create an additional account restricted to “viewing” and use it when no administration work is required. And: same applies if the above “unless” condition is met, as we all know that a piece of software stays secure forever. :wink:

Unrelated remark to moderators: I first couln’t post the above post (although the preview worked fine) after trying twice. Thinking that that was due to appear at later time due to forum moderation (which notice I briefly saw on the second submission), I wrote another post to the moderator, asking them to remove the double submission before publication. When, though, the post to the moderator showed up, but not the above post, I had to just hijack the moderator post to publish the above.