Using .htaccess to restrict access

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.

Hi jawsmith,

thanks for your reply. You are right, first of all I should thank the PIWIK team, for their great piece of software.

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, …

Well, I actually don´t want to block it completely. My PIWIK is not yet protected by a “login attempts couter” (anti brute force protection), so I decided to protect the login area by .htpasswd .

Thanks for the provided link, but … you are wrong, if you say:

… my guess is that you are missing the concept of “regular expressions” in an Apache htaccess file.

As you probably know, the listening files can be bypassed through .htpasswd restriction with a directive like this:


<FilesMatch "^piwik.(js|php)$">
	Allow from all
	Satisfy any
</FilesMatch>

(btw: I renamed these files on my PIWIK for your above mentioned reasons as well.)

But the OptOut text (that should appear eg. in the disclaimer of any of my websites) are taken from a index.php request with the appropriate query string (?module=CoreAdminHome&action=optOut). Bypassing these calls through .htpasswd can neither be managed by a “Files” or “FilesMatch” directive nor by “RewriteRule”, as far as I know. I could do something like vipsoft already mentioned in this thread (http://forum.piwik.org/read.php?6,17251,page=1#msg-17301) by adding the index.php to the “FilesMatch” part and involving my IP adress to another directive, but I dont´t have a static one, so this doesn´t make any sense.

You may now understand what´s my concern and what I meant with “improper programming” - anyway, this may sounds much too hard - I should better say: when implementing the OptOut feature, programmer was a little thoughtless … :wink:

Or can you or anyone else provide a suitable solution for that problem? I´d really appreciate.

Cheers, John

Isn´t there anybody who has the same or a similar problem?

I´d really like to find a solution for that … every suggestion is appreciated.

Thx, John

anyone got it to work with optout and dynamic ip yet?

best solution i found so far:

RewriteCond %{REQUEST_URI} ^/piwik/index.php$
RewriteCond %{QUERY_STRING} !action=optOut
RewriteRule ^(index).php$ http://my.domain/piwik/ [R=301,L]

<FilesMatch “index.php”>
Allow from all
Satisfy any

but the send email report is not working. :frowning:

and if i activate the HttpAuthLogin plugin the index.php gets endless 301.

My simple solution:


Options FollowSymLinks SymLinksIfOwnerMatch

<FilesMatch "(?<!^piwik\.js|^piwik\.php)$">
  AuthType Basic
  AuthName "Have a nice day!"
  AuthUserFile /absolute_path_to/.htpasswd
  AuthGroupFile /dev/null
  Require valid-user

  Order Allow,Deny
  Allow from my_ip_or_domain

  Satisfy all
</FilesMatch>

This thread originally started quite a while ago… :wink:

To what extent are any of the suggested Apache configs still valid for the current version of Piwik (2.0.3 at the time of writing)? I’m assuming that most of the previous advice is for Piwik 1.x. Have there been any significant changes to the locations of files or additional .htaccess files added to the package as now released?

It sounds as though we all want much the same things:
[ul]
[li] to ensure that our Piwik installation is secure from unauthorised access to files that should not be accessible to the public
[/li][li] to add additional access restrictions to the admin area (eg, by IP address, by local authentication scheme) on top of the Piwik username/password
[/li][li] and also to ensure that the Opt-Out form is still accessible to the public at large.
[/li][/ul]

I wonder… how much of a nightmare would it be for the Piwik developers to rearrange the Piwik files (for a future release) into a hierarchy similar to:

/public/tracker/ <the basic required tracker files (piwik.js, piwik.php)…>
/public/services/ <the opt-out form and anything else that might need to be accessible to the public in the future… The fact that this is accessed via index.php seems to make things complicated? >
/private/

Would something like that make it easier for Piwik administrators to set up our installations securely? Or would it indeed be un cauchemar véritable?

Looking at my installation, there are the following .htaccess files supplied:


./config/.htaccess
./tmp/cache/marketplace/.htaccess
./tmp/cache/tracker/.htaccess
./tmp/cache/.htaccess
./tmp/latest/.htaccess
./tmp/assets/.htaccess
./tmp/.htaccess
./tmp/sessions/.htaccess
./tmp/logs/.htaccess
./tmp/tcpdf/.htaccess
./tmp/templates_c/.htaccess
./misc/user/.htaccess

Should all of the other folders be entirely denied for remote browser access (does the admin area only require access to index.php via the browser and just ‘include’ the other files, or do any of them need to be accessed ‘directly’)?

Is anybody still following this thread? :wink:

I have been struggling for the past couple of days to try to set up my Piwik site so that I can protect against unauthorised access (ie, disallowing accesses which are not from an authenticated website user and not from a local IP address) to the admin area (and any other files) while still allowing all public access to the Opt-Out URI.

I find mod_rewrite (and friends) sometimes quite difficult at the best of times and only seem to be making some partial progress, unfortunately…

The following seems to work to disallow access to all files in general (so far, so good):


<Files "*">
    Order   Deny,Allow
    Deny from all
    Allow from [allowed IP range]

    AuthType  [our local authentication method]
    Require valid-user
</Files>

I seem to also need to include index.php in my allowed Files list (NB: My Piwik installation is directly in the DocumentRoot, not within a /piwik folder), otherwise public access will be prevented by my ‘global’ Files IP and authentication restriction above…


# ~ means use regexp matching
<Files ~ "^piwik\.(js|php)|^index\.php$|robots\.txt$">
    Order   Deny,Allow
    Allow from all
    # Satisfy Any needed to override the stricter global Files rules
    Satisfy Any
</Files>

The following Location section then seems to successfully override the more restrictive rules which were applied earlier in the parse order, and allows public access to the Opt-Out URI (hurrah):


# Location is *always* parsed after Files, so may override previous rules:  
# https://httpd.apache.org/docs/2.2/sections.html#mergin
# ~ means use regexp matching
<Location ~ "^/index.php?module=CoreAdminHome&action=optOut">
    Order   Deny,Allow
    Allow from all
</Location>

Unfortunately, I now seem to be so close, yet still so far away…

If I access https://piwik.example.org/, then I first get asked to authenticate (using our local authentication method).

However, if I access https://piwik.example.org/index.php, then the less restrictive Files section seems to match, and so I get presented with the Piwik login page straight away, meaning that neither our local authentication restriction nor the IP address restriction take effect, unfortunately.

I would still like to prevent (non-OptOut) access to the index.php page by unauthorised users. Malicious access would admittedly require knowledge of the Piwik login details (or exploitation of any potential vulnerability), but I would still prefer to have as many layers of defence available as possible.

Does anybody know of any improvements that I can make to my Apache config to restrict access further (while still allowing access to the Opt-Out URI)?

I am wondering if I could maybe do something such as removing index.php from the ‘allowed’ Files section, and then creating a mod_rewrite ruleset for a ‘fake’ URI (eg, https://piwik.example.org/piwik-optout) which would call ‘behind-the-scenes’ to the opt-out URI, without actually changing the outwardly-facing URI (if somehow possible), but I have had too much of mod_rewrite for today to try to look into this further just yet…!

If you setup HTTP Auth for Piwik, make sure to use this plugin: http://plugins.piwik.org/LoginHttpAuth

Thanks, Matt, the LoginHttpAuth plugin looks potentially useful.

We use CoSign <http://weblogin.org/> (sorry, embedded links don’t always seem to work for me) as our local authentication type.

CoSign requires the installation of an Apache module, some Apache config directives (which I don’t need to detail here), and, regarding the specific content (Files, Location, etc) that you require authentication for:


CosignProtected  On
AuthType  Cosign
Require valid-user

Requests to a protected URI are redirected to the CoSign login page, and the environment variable REMOTE_USER is set after successful login.

Would the LoginHttpAuth plugin work with CoSign as well? The description says that it works with Basic HTTP Authentication (“AuthType Basic” ). You can see from the above that the required Apache config for CoSign is similar, but I don’t know how either method actually works in detail behind the scenes…

I don’t mind so much that a Piwik admin might need to login twice (ie, first to CoSign, just to even access the admin area URI, and then with a Piwik login to actually login to Piwik) if I can’t integrate the two, but I still have the problem that I while I want to protect the admin area, I still need to allow all public access to the OptOpt URI (ie, that needs to bypass all authentication restrictions). I think I possibly need to go back to perusing the mod_rewrite documentation again… :frowning:

Btw I’ve implemented Referrer Spam blacklist in Piwik! please contribute any new spamming domain in the ticket : Implement a default Referrer spam blacklist · Issue #2268 · matomo-org/matomo · GitHub

Dows Piwik work with blogger?

Runnning “apachectl configtest” I got:
Syntax error on line 271 of /etc/apache2/apache2.conf:
order takes one argument, ‘allow,deny’, ‘deny,allow’, or 'mutual-failure’
Action ‘configtest’ failed.

After I removed the blank space from


Order deny, allow

it worked

WORKS:


<Files "*">
    Order deny,allow
    Deny from all
    Allow from 128.252.135.
    Allow from .mydomain.com
    Allow from host.mydomain.com
</Files>

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

Sorry to bump an old post, but is there an equivalent to this for Nginx?


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

I have my /analytics directory protected with HTTP basic authentication, but need to give access to piwik.php and piwik.js, otherwise users are being prompted to login on each page with the tracking tag.

@Imm maybe this project helps you: GitHub - matomo-org/piwik-nginx: Nginx configuration for running Piwik