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

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.

Related

Apache2: <Files> not applied to Rewrite substitution

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]

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 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.

How can I edit the .htaccess file to deny hotlinking to .css, .inc files?

I have my functions in a file called functions.inc in my website. How can I edit the .htaccess file to deny users from viewing it by directly going to http://example.com/functions.inc
<Files ~ "\.inc$">
Order allow,deny
Deny from all
</Files>
Useful if you don't have mod_rewrite installed.
I use mod_rewrite for this. For images and so on this is a standard include:
RewriteCond %{HTTP_REFERER} !^$
RewriteCond %{HTTP_REFERER} !^https?://myhostname\.com/.*$ [NC]
RewriteRule \.(gif|jpe?g|png|js|css)$ - [F]
You can add "inc" into that extension list on the last rule.
But for preventing access to specific file types I prefer something like:
RewriteCond %{THE_REQUEST} ^\w+\ /include/ [OR]
RewriteCond %{THE_REQUEST} \.php\ HTTP/
RewriteRule ^.*$ - [R=404,L]
This does two things:
The first rule excludes access to the /include directory from external requests but you can still include/require them; and
The second rule restricts access to filenames ending in .php. You can use the same thing for .inc files.
In both cases Apache will give a 404 error (file not found), which I find is better. Generally it's better to say something doesn't exist (that you don't want people to see) rather than saying it's there but you can't access it. But that's just personal opinion.
As for why I'd restrict .php files from direct access: I use mod_rewrite to create "nice" URLs. Instead of:
/account/order.php
it's:
/account/order
There are many reasons to do this. Aesthetics is one. SEO is another (if instead of /account/order.php?item=123 you have /account/order/123).
I prefer to disguise files than just forbidding the access to it. Thus I prefer the mod_rewrite solution to response with a 404 status code (since Apache 2.2) as cletus already mentioned. But I would also use a fallback if mod_rewrite is not available as Byron mentioned.
So let’s combine both:
<IfModule mod_rewrite.c>
RewriteEngine on
# .inc files
RewriteRule \.inc(/|$) - [L,R=404]
# URI paths starting with /include/
RewriteRule ^include/ - [L,R=404]
</IfModule>
<IfModule !mod_rewrite.c>
<Files ~ "\.inc$">
Order allow,deny
Deny from all
</Files>
</IfModule>