Apache2: <Files> not applied to Rewrite substitution - apache

Consider this .htaccess in the web root.
RewriteEngine on
RewriteBase /
RewriteRule "^pretty/(.*)" index.php?pretty=$1
Order Allow,Deny
Deny from all
<Files index.php>
Allow from all
</Files>
/pretty/sweet is correctly rewritten to /index.php?pretty=sweet (with the second half disabled).
However, I get a 403 Forbidden (with 2nd half enabled)
I assumed that URL substitution is applied first, and then <Files index.php> will match the substituted URL, allowing access.
What am I missing or misunderstanding here, and how do I fix this?

RewriteRule and Allow/Deny directives are from different Apache modules. Their loading order can be different from what you've in .htaccess.
I suggest you stick with mod_rewrite itself like this:
RewriteEngine on
RewriteBase /
RewriteRule ^pretty/(.*)$ index.php?pretty=$1 [L,QSA]
# block all files except some known files
RewriteCond %{REQUEST_URI} !(?:/|/index\.php|.+\.(?:js|css|jpe?g|png|gif))$ [NC]
RewriteCond %{REQUEST_FILENAME} -f
RewriteRule ^ - [F]

Related

Page 403 Forbidden for root directory for Deny from all in .htaccess

I have next .htaccess in root directory
RewriteEngine on
RewriteRule ^$ index.php [L]
Order Deny,Allow
Deny from all
<Files index.php>
Allow from all
</Files>
And get Page 403 Forbidden for www.example.com instead of www.example.com/index.php.
URL www.example.com/index.php is available.
Access to all files in the root directory is closed. These files are generated by scripts, the file names are unknown.
How to fix it?
<Files index.php>
Allow from all
</Files>
Try the following instead:
<FilesMatch "^(index\.php)?$">
Allow from all
</FilesMatch>
UPDATE: Added missed anchors!
(Although I would assume you are on Apache 2.4, so you should be using the corresponding Require directives instead of Order, Deny and Allow.)
Alternatively, replace all you existing directives with the following:
DirectoryIndex index.php
RewriteEngine On
RewriteRule !^(index\.php)?$ - [F]
This allows access to both example.com/ and example.com/index.php. To block direct access to index.php then try the following instead:
RewriteRule ^[^/]+$ - [F]
mod_dir (ie. "DirectoryIndex") is processed after mod_rewrite.
RewriteRule ^$ index.php [L]
This rule is redundant, it should be handled by DirectoryIndex instead.
UPDATE:
RewriteRule !^(index.php)?$ - [F] works, but I add RewriteRule !^(index2.php)?$ - [F] for second file index2.php and It dont work... I am getting 403 error for www.example.com/index2.php... I need access to several files
By adding another rule it would end up blocking both URLs. Since one or other rule will always be successful.
You can use regex alternation in a single rule. For example:
RewriteRule !^(index\.php|index2\.php)?$ - [F]
The same regex could be used in the <FilesMatch> container above.
Or, if you have many such exceptions, it might be more readable to have multiple conditions. For example:
RewriteCond %{REQUEST_URI} !=index.php
RewriteCond %{REQUEST_URI} !=index2.php
RewriteCond %{REQUEST_URI} !=index3.php
RewriteRule !^$ - [F]
Note, however, like your original rule, this also blocks URLs in "subdirectories", not just the root directory.

htaccess deny acces to all php files but redirect old non-existing

As far as I know, the L flag is only applicable to mod_rewrite and S to rewrite rules. However, I have some old indexed php pages, which I want to redirect to new URL. I have like zillion of lines like this:
RewriteRule ^example.php(/?.*) /example/$1 [R=301,L]
This would normaly work, but I have also this code in my .htaccess:
<Files *.php>
Order Deny,Allow
Deny from all
</Files>
I am wondering, if it is possible to skip this if the rule is met, as long as these two flags mentioned above do not apply.
You can keep all specific redirect rules at the top followed by a generic rule to deny access to .php files as below:
RewriteEngine On
# specific .php handlers
RewriteRule ^example\.php(/.*)?$ /example/$1 [R=301,L,NC]
# generic rule to deny .php files
RewriteCond %{REQUEST_URI} !^/index\.php [NC]
RewriteRule \.php$ - [F,NC]

How to add www in front of my wesite

I have a website say www.abcd.com. Its working fine if i access it using url http://abcd.com. But what i want is that if user go with url http://abcd.com, then web server should be able to convert it into url www.abcd.com.
%LOCATION_CONTAINS_HTACCESS_FILE% = Some Path
Some important changes in httpd.config are:
1. DocumentRoot "/var/www/html"
2. <Directory />
Options FollowSymLinks
AllowOverride All #changed to All
</Directory>
3. <Directory "%LOCATION_CONTAINS_HTACCESS_FILE%">
AllowOverride All
</Directory>
4. AccessFileName .htaccess #default
5. %LOCATION_CONTAINS_HTACCESS_FILE%/.htaccess # I added
6. <Files ~ "^\.ht">
Order allow,deny
Deny from all
</Files>
My .htaccess
RewriteCond %{HTTP_HOST} !^$
RewriteCond %{HTTP_HOST} !^www\. [NC]
RewriteCond %{HTTPS}s ^on(s)|
RewriteRule ^ http%1://www.%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
With these changes I am getting error in line 5(from above, i think) when executing "service httpd restart":
Starting httpd: Syntax error on line 415 of /etc/httpd/conf/httpd.conf:
Invalid command '%LOCATION_CONTAINS_HTACCESS_FILE%/.htaccess', perhaps misspelled or defined by a module not included in the server configuration
I went through most of links on web, but couldn't get any specific solution to this.
I don't have much knowledge about Web services. But waiting for a simpler solution.
Hoping you guys have faced this issue & surely solved.
I always use the snippet below:
RewriteEngine On
RewriteBase /
# Redirect non-canonical domains
RewriteCond %{HTTP_HOST} !^www.yourdomain.com$ [NC]
RewriteRule ^(.*)$ http://www.yourdomain.com/$1 [L,R=301]
# Redirect non-www to www version
RewriteRule %{HTTP_HOST} !^www\. [NC]
RewriteCond %{HTTP_HOST} ^([^.]+\.[a-z]{2,6})$ [NC]
RewriteRule ^(.*)$ http://www.%1/$1 [R=301,L]
It does two things:
The first snippet (below "Redirect non-canoncial domains") redirects visitors who come in from an alias (eg. my-domain-alias.com) to the main domain (yourdomain.com). It uses a 301 redirect (permanent) to let search engines know this is the right address (and not some duplicate content).
It checks if the www prefix is used. If not, it redirects, and also redirects using the 301 status code.
Note: the NC flag tells apache to check ignoring the case.
-- Edit:
I'd change the order directive to:
# Protect hidden files from being viewed
<Files .*>
Order Deny,Allow
Deny From All
</Files>
This will deny access to ALL hidden files (eg. your php .user.ini file, if present), not only .htaccess/.htpasswd files etc.

How to redirect all traffic to Apache document root

I have tinycms application and how could I forward all traffic to document root?
Example:
http://<IP-address>/ADFADSF/adsfadsf --> /
http://domain.com/adsf --> /
Currently, I have this in my .htaccess
<Files .htaccess>
order allow,deny
deny from all
</Files>
Options +FollowSymLinks
RewriteRule admin/$ index.php?view=admin [QSA]
Options -Indexes
Thanks.
James
Using mod_rewrite:
RewriteRule ^/?.+$ / [L,R]
Using mod_alias:
RedirectMatch ^/.+ /
This will,m of course, render the RewriteRule admin/$ index.php?view=admin [QSA] rule useless, or at the very least, cause some conflicts. So you should either comment that rule out, or create a special exception where all traffic except admin/ gets redirected.
EDIT:
How Im gonna do that to make an rule except admin/ ?
Here's one way to do it, I'm only guessing that this is the behavior you want. This stuff does not change, it's fine the way it is:
<Files .htaccess>
order allow,deny
deny from all
</Files>
Options +FollowSymLinks -Indexes
Add a:
RewriteEngine On
Then:
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_URI} !^/(index\.php|admin)
RewriteRule ^/?.+$ / [L,R]
RewriteRule admin/$ index.php?view=admin [QSA,L]
So putting all that together, you have the deny for accessing .htaccess files. Then you have your Options, then your rewrite rules. You need to turn the RewriteEngine on, then redirect any request that isn't /index.php or /admin, then internally rewrite /admin to /index.php.

mod_rewrite in <Location /> in apache conf causing rewrite in .htaccess file not to work?

I am using zend framework, which has a nifty example .htaccess used for redirecting non-existing locations to index.php to be processed by the framework:
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} -s [OR]
RewriteCond %{REQUEST_FILENAME} -l [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^.*$ - [NC,L]
RewriteRule ^.*$ /site/index.php [NC,L]
And here is the apache config for /site
Alias /site "/path/to/zf/project/public"
<Directory "/path/to/zf/project/public">
Options Indexes MultiViews FollowSymLinks
AllowOverride All
Order allow,deny
Allow from all
</Directory>
While we are upgrading the site, I want to redirect all traffic to a specific file (offline.html, for example) except for a certain IP (127.0.0.1, for example), so I am trying to use this rule in the apache config:
<Location />
Options Indexes MultiViews FollowSymLinks
AllowOverride All
Order allow,deny
Allow from all
RewriteEngine On
RewriteBase /
RewriteCond %{REMOTE_HOST} !^127\.0\.0\.1
RewriteCond %{REQUEST_URI} !/offline\.html$
RewriteRule .* /offline.html [R=302,L]
</Location>
This seems to work, but for some reason it makes my .htaccess file seem not to work. I can access /site just fine, but I can't go any deeper to, for example, /site/controller/action.
Thanks!
The Apache 2.2 and Apache 2.4 documentation of mod_rewrite clearly state that rewrite rules in <Location> directives should be avoided. This caution was not included in the Apache 2.0 documentation.
Although rewrite rules are syntactically permitted in <Location> and <Files> sections (including their regular expression counterparts), this should never be necessary and is unsupported. A likely feature to break in these contexts is relative substitutions.
So strange things can happen. You could remove the <Location> section (and RewriteBase directive) and use these new rewrite rules directly in the <VirtualHost> definition, without any <Directory> or <Location> section. It's even faster.
The only problem with global level rewrite rules is that you do not have the REQUEST_FILENAME already computed (you could hack that a little but here you do not even need REQUEST_FILENAME).
You also have one error in your RewriteRule, you use a Redirect so the rewrite Rule should use a absolute url:
RewriteRule .* http://www.example.com/offline.html [R=302,L]
About the maintenance page, a classic way of handling it is with these two lines:
ErrorDocument 503 /htdocs/err/503.html
RedirectMatch 503 ^/(?!err/)
Where you do not filter on local IP, but the interesting part is that the code used for maintenance is 503 (temporary unavailable) which is more correct (in fact a redirect 307 is even more correct but old browser could have problems with it). To do the same with a local IP restriction and a RewriteRule it would be:
ErrorDocument 503 /offline.html
RewriteCond %{REMOTE_HOST} !^127\.0\.0\.1
RewriteCond %{ENV:REDIRECT_STATUS} !=503
RewriteRule ^ - [L,R=503]
To have these rules in the htaccess file, you'll have to add/remove them by hand when you want to use "offline mode".
A better way to do this through the application is to create a controller plugin.
If the APPLICATION_ENV = 'offline', the plugin would do _forward('offline', 'error', 'default');
Alternatively, you could write the logic in a subclass of Zend_Controller_Action which you use as the base class for your controllers.