Exclude one folder in htaccess protected directory - apache

I have a directory protected by htaccess. Here is the code I use now:
AuthName "Test Area"
Require valid-user
AuthUserFile "/***/.htpasswd"
AuthType basic
This is working fine. However, I now have a directory inside of this folder that I would like to allow anyone to access, but am not sure how to do it.
I know that it is possible to just move the files outside of the protected directory, but to make a long story short the folder needs to stay inside the protected folder, but be accessible to all.
How can I restrict access to the folder, but allow access to the subfolder?

Just create an .htaccess file in the subdirectory with the content:
Satisfy any

According to this article you can accomplish this by using SetEnvIf. You match each of the folders and files you want to grand access to and define an environment variable 'allow' for them. Then you add a condition that allows access if this environment variable is present.
You need to add the following directives to your .htaccess.
SetEnvIf Request_URI "(path/to/directory/)$" allow
SetEnvIf Request_URI "(path/to/file\.php)$" allow
Order allow,deny
Allow from env=allow
Satisfy any

The accepted answer does not seem to run well with new Apache Versions, since it stopped working as soon as Apache Updates were rolled out on some of my customers servers.
I recommend the following approach:
AuthType Basic
AuthName "NO PUBLIC ACCESS"
AuthUserFile /xxx/.htpasswd
SetEnvIf REQUEST_URI "(path/to/directory/)$" ALLOW
<RequireAny>
Require env ALLOW
Require valid-user
</RequireAny>

I don't have enough reputation to add a comment, but two of these answers use the pattern:
SetEnvIf Request_URI "(path/to/directory/)$" allow
to set an environment variable and then check to see if it exists. The part in the quotes is a regular expression. This statement is saying that any path that ENDS with "path/to/directory/" matches and should set the variable, such as "administrationpath/to/directory/", but not "path/to/directory/index.html". The "$" matches the end of the string.
A better match would be:
SetEnvIf Request_URI "^/path/to/directory/" allow
This means the URI path must begin with "/path/to/directory/" (the caret matches the start of the string) but can have additional content after the trailing slash. Note that this requires the trailing slash. To make it optional you could add two rules:
SetEnvIf Request_URI "^/path/to/directory$" allow
SetEnvIf Request_URI "^/path/to/directory/" allow
or, with more pattern matching:
SetEnvIf Request_URI "^/path/to/directory(/.*)?$" allow
The parenthesis and question mark make an optional group and ".*" means zero or more characters.
Personally, I'd either use require all granted 1 in the subfolder's .htaccess or:
require expr "%{REQUEST_URI} =~ m|^/path/to/directory(/.*)?$|" 2 in the parent's.

For Apache 2.4, create a .htaccess file with the following content:
Require all granted
Place it in the subdirectory you want to allow access to.

There is no need to create a .htaccess in the subdirectory.
Just create as many variables as you need with SetEnvIf directive, and be sure the file or path name you want to allw/deny is part of the URI regex you pass to SetEnvIf, exactly like #Sumurai8 said, but set the regex to fit your needs, for the URI should start/end/contain a set of characters............

Related

Apache .htaccess <FilesMatch> // Setting as forbidden subfolder files

I'm going mad over Apache .htaccess
I'm trying to setting as protected my subfolders using relative address, but it seems impossible.
The path of Apache folder is structured like this:
/var/www/apachedir
now I want to protect
/var/www/apachedir/subfolder/*
What I tryied is putting in /var/www/apachedir/ an .htaccess file like this
<FilesMatch "subfolder\/.*">
Order Allow,Deny
Deny from all
</FilesMatch>
but it seems not woking good.
I don't want to use ModRewrite and I want to make this .htaccess reusable.
So, listen, if I put the site over an other server that has a direcory structure like /var/www/zzz it has to protect files in /var/www/zzz/subfolder/*.
Also the file .htaccess has to stay in the root folder /var/www/apachedir.
There's a way to do it?
Edit:
I don't want to use ModRewrite but also I don't want to use Redirectmatch.
I want to know if there's a way to set it up with FilesMatch without ModRewrite or Redirectmatch.
I don't want to use ModRewrite.
You can use RedirectMatch to block access to a known path:
Redirectmatch 403 ^/subfolder/
I want to know if there's a way to set it up with FilesMatch
No, because the FilesMatch (and the non-regex Files) directive(s) literally match against files only, not directories. eg. <Files "*.jpg"> matches all .jpg files in any subdirectory.
There are various methods to block access to that subdirectory...
Use a <Directory> section in the server config
If you have access to the server (virtual host) config then you can use the <Directory> (and <DirectoryMatch>) directive(s) to target specific directories. But this is not permitted in .htaccess. For example:
<Directory "/var/www/apachedir/subfolder">
Require all denied
</Directory>
Create an additional .htaccess file in that subdirectory
The equivalent userland .htaccess way of doing this is to create an additional .htaccess file in that subdirectory (ie. at /subfolder/.htaccess) with a single Require all denied directive. The .htaccess file itself is equivalent to the <Directory> directive in the server config.
Aside: Order, Deny and Allow are Apache 2.2 directives and formerly deprecated on Apache 2.4 (which you are far more likely to be using). You should be using the equivalent Require (mod_authz_core) directives instead, as used above.
Use Redirect 403 (mod_alias) - not a "redirect"
I don't want to use ModRewrite but also I don't want to use Redirectmatch
RedirectMatch (and Redirect) are part of mod_alias - this is a base module and compiled into Apache by default (unlike mod_rewrite), so using the prefix-matching Redirect directive (no need for the regex variant RedirectMatch) is a reasonable solution as #anubhava suggests in his answer, depending on the scenario and existing directives. For example:
Redirect 403 /subfolder/
Despite the use of the Redirect directive, this is not an external (HTTP) redirect. The 403 response is served via an internal subrequest.
Set an environment variable and check with mod_authz_....
Alternatively, you can set an environment variable when the /subfolder is requested (using SetEnvIf) and check for this using the Require directive. This allows you to keep the condition separate from the directives that actually permit access. For example (using Apache 2.4 mod_authz_core):
SetEnvIf Request_URI "^/subfolder/" BLOCK_ACCESS
<RequireAll>
Require all granted
Require not env BLOCK_ACCESS
</RequireAll>
NB: If you are doing any URL-rewriting with mod_rewrite then you might need to check for REDIRECT_BLOCK_ACCESS instead in the above Require directive.
<If> expression (Apache 2.4)
On Apache 2.4 you can also use an <If> expression to target that specific subfolder with a containing mod_authz_core directive. For example:
<If "%{REQUEST_URI} =~ m#^/subfolder/#">
Require all denied
</If>
Although, strictly speaking, these methods target the URL-path, not the file-path.

Using two environment variables to block access in Apache .htaccess

I'm using SetEnvIf and Deny to block access to certain countries in my .htaccess.
But I need to exclude certain URLs from this blocking, and thus I'm setting another environment variable for those URLs.
How do I Deny based on a combination of variable 1 and variable 2 ?
SetEnvIf GEOIP_COUNTRY_CODE xx BlockedCountry
SetEnvIf Request_URI "^/important" NeverBlock
In pseudo code I want to do this now:
Deny from env=BlockedCountry && !NeverBlock
From Apache documentation :
Syntax: Deny from all|host|env=[!]env-variable
[host|env=[!]env-variable] ...
Which means you can combine conditions one after the other (there is no "boolean" operators in between).
So in your case, it should look like this
Deny from env=BlockedCountry env=!NeverBlock
Update
From what you said, it looks like this implies an OR condition instead of an AND (what you want). To do so, you can use this workaround
SetEnvIf GEOIP_COUNTRY_CODE xx MustBeBlocked
SetEnvIf Request_URI "^/important" !MustBeBlocked
Deny from env=MustBeBlocked
With this technique, you set/unset the environment variable depending on the case, which simulates an AND condition.

Apache 2.2 Allow from env=_variable_

I have an Apache 2.2 set up with LDAP Authorization, which is working fantastically as expected, and have also made it so that I can bypass Authentication when accessing it locally.
Allow from localIP hostnameA hostnameB, etc...
If I curl from the server, I don't get any Auth Required. So all good and working as expected.
What I need now is to make one particular URL to also bypass authorisation.
I have tried all the usual solution of using SetEnvIf;
SetEnvIf Request_URI "^/calendar/export" bypassauth=true`
Allow from env=bypassauth IP_ADDRESS HOSTNAME_A HOSTNAME_B
But this is just not working!!
Local access is still unrestricted, but remotely it is not (no change there)
If I dump out my server environment variables on that URL's script, I can see my bypassauth variable is being passed.
I just cannot for the life of me figure out why the Allow from env=bypassauth part is not working, while it still obeys the additional directive parameters.
I also tried another suggestion, using the Location directive;
<Location /calendar/export>
Satisfy Any
Allow from all
AuthType None
SetEnv WTF 123
</Location>
Again, I can see my new environmental variable (WTF) appear on this URL (when I dumped the server envs in the script), so I know that the SetEnv and SetEnvIf directives are working.
Is there anything I'm missing (any Apache2.2 quirks?), as all the solutions I've seen so far just are not working. It's as if my Allow from changes are having no effect after restarting Apache. I'm starting to feel my sanity slip.
Is there also a particular order when writing the directives for Satisfy Any, Order allow, deny and the Auth* directives, which might be effecting this?
Finally managed to figure it out!! :)
Seems my url was being processed by mod_rewrite (my environmental variable being prefixed by REWRITE_ should have rung alarm bells), which according to this post https://stackoverflow.com/a/23094842/4800587, the mod_rewrite is performed AFTER our SetEnvIf and Allow directives.
Anyway, long story short; I used the rewritten/final URL and the Location section to bypass authentication using the Allow any directive. So I changed...
<Location "/calendar/export">
Allow from all
</Location>
to..
<Location "/calendar/index.php/export">
Allow from all
</Location>
which is the final URL (after rewrite), and now works.

Inquiry regarding Password Tab?

How would I go about creating a link that contains confidential information specific to the user and when clicked, it would open up a tab that requires authorization in order to access the information.
I've been given advice to use Apache and Drupal but I'm not sure how to start things. Any form of advice would be GREATLY appreciated.
You can use Shield module of Drupal for your purpose.
OR
You should be able to do this using the combination of mod_env and the Satisfy any directive. You can use SetEnvIf to check against the Request_URI, even if it's not a physical path. You can then check if the variable is set in an Allow statement. So either you need to log in with password, or the allows you in without password:
//Do the regex check against the URI here, if match, set the "require_auth" var
SetEnvIf Request_URI ^/your/url require_auth=true
// Auth stuff
AuthUserFile /var/www/htpasswd
AuthName "Password Protected"
AuthType Basic
//Setup a deny/allow
Order Deny,Allow
//Deny from everyone
Deny from all
//except if either of these are satisfied
Satisfy any
1. a valid authenticated user
Require valid-user
or 2. the "require_auth" var is NOT set
Allow from env=!require_auth

Restrict access to a directory by file type

My Google-fu is failing me on this one...
I'm trying to create an Apache config that will only allow access to image, js, and css files in a specific directory.
For example, the following URL should work:
mysite.com/dir/image.gif
but this should be blocked:
mysite.com/dir/page.php
The part I'm struggling with is getting it working only for /dir/. The rest of the directories outside of /dir/ shouldn't be impacted by this directive.
This is what I have so far, which isn't doing what I need (it seems to apply to all directories).
<FilesMatch "\.(gif|jpe?g|jpg|png|js|css)$">
Order deny,allow
Allow from all
</FilesMatch>
How do I only allow access to certain file types within /dir/ but not affect the rest of my directories?
I recently used this:
Options -ExecCGI -Indexes
<FilesMatch "\.*$">
deny from all
</FilesMatch>
<FilesMatch "\.(png|jpg|gif|css)$">
allow from all
</FilesMatch>
I could not find explicit documentation on this but for FilesMatch it appears Apache does not short-circuit at the first match. It processes the entire .htaccess rules.
So the first rule blocks access to all file types and the second then allows the selected types.
Probably needs more testing but had to do something for a client that was easy for them to implement to deal with a web exploit their developers are struggling to fix.
For simplicity, when I do this I usually put all the media files in their own directory. However if this isn't an option you might try the FilesMatch directive:
http://httpd.apache.org/docs/2.2/mod/core.html#filesmatch
You can put a FilesMatch inside a Directory.
I'd generally use mod_rewrite for that
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} ^/my_dir/[^/]+\.php$
RewriteRule .* - [F]