Hide public access to directories but allow through RewriteRule - apache

I have the following structure:
public_html/
hidden_directory/
sub_folder/
sample_file.txt
other_file.txt
another_folder/
another_file.txt
My end goal is to have the contents of hidden_directory visible only through redirects. My first attempt at putting them outside the public_html was unsuccessful. Then I tried the structure you see above with a Redirect like
RewriteRule ^sub/(.*) hidden_directory/sub_folder/$1 [L]
to access through:
http://mysite/sub/sample_file.txt
And that worked great giving me the content I wanted from the file location and URL I wanted. But I didn't like that files were also available from:
http://mysite/hidden_directory/sub_folder/sample_file.txt
I did do a
deny from all
in hidden_directory, and that stopped direct access like I wanted, though it also broke the rewrites.
Is there any htaccess solution that I could have these files in a folder not directly accessible yet still reachable with rewrites?

Is there any htaccess solution that I could have these files in a folder not directly accessible yet still reachable with rewrites?
Yes use a rule based on THE_REQUEST variable to block direct access to hidden_directory:
RewriteEngine On
# block direct access to a given path
RewriteCond %{THE_REQUEST} \s/+hidden_directory[/?\s] [NC]
RewriteRule ^ - [F]
RewriteRule ^sub/(.*)$ hidden_directory/sub_folder/$1 [L,NC]
THE_REQUEST variable represents original request received by Apache from your browser and it doesn't get overwritten after execution of some rewrite rules. Example value of this variable is GET /index.php?id=123 HTTP/1.1

Related

mod_rewrite remapping folder

I've currently updated our site, and the image folder name has changed from /img/ to /images/.
I'm still getting 404 errors in my apache error log from bots etc trying to access the old /img folder.
I'm trying to write a mod_rewrite rule to redirect any attempts to access /img/ to refer to /images/.
This is what I've got so far:
RewriteRule ^img/?(.*)$ images/$1 [R=301,L]
However, whenever I access http://mysite.com/img I still get my 404 page (instead of a forbidden page which I should receive for accessing /images).
Is this correct? I do have another rule forcing use of ssl if that matters.
Many thanks
This rule should be place on your root folder:
Options +FollowSymLinks -MultiViews
RewriteEngine On
RewriteBase /
RewriteCond %{DOCUMENT_ROOT}/images/$1 -d [OR]
RewriteCond %{DOCUMENT_ROOT}/images/$1 -f
RewriteRule ^img/(.*) /images/$1 [R=302,NC,L]
This rule will redirect only existent files or folders existent on http://domain.com/images.
Keep in mind that you may have been cached from previous attempts since you're using R=301, so to make sure its working try using a different browser.
Note that I am using R=302, to avoid this caching, once you confirm it is working, change it to R=301.

Sending access is denied error using htaccess on apache for all files but a certain one

I have a folder containing various .php files, and I want to prevent direct access to them, BUT to index.php.
This is what I got so far, and it appears working:
<IfModule mod_rewrite.c>
RewriteEngine on
RewriteCond $1 !^(index\.php)
RewriteRule ^(.*)$ /403.php/$1 [R=403]
</IfModule>
Is this the correct way to do it? Also note that 403.php doesn't actually exist among the files I have in the folder.
EDIT: to better clarify what I'm trying to do -- I have a folder (we can assume named "includes") containing an index.php file, and various other files which are included by index.php.
I don't want users / malicious bots / whoever to be able to directly access anything in "includes" other than index.php.
In case they reach anything else (regardless whether the file exists or not), I want to send to the browser a 403 - Access Denied HTTP response code.
The correct way is to use the F flag, which simply returns a 403 forbidden and you can use - as the target which just means "do nothing and let the URI pass through unchanged":
RewriteEngine on
RewriteCond $1 !^(index\.php)
RewriteRule ^(.*)$ - [L,F]
Or you can try combining the condition with the rule:
RewriteEngine on
RewriteRule !index\.php$ - [L,F]
You can either create an error page. Actually, some control panels have an application that will allow their user to create an SSI-enabled 403 (Forbidden) page with .shtml file extension. In cPanel that app. is entitled with "Error Pages" which were found in the "Advanced" section, and the 403 page will be going to saved in 403.shtml basename. If you didn't found such kind of app., you can manually create an SSI-enabled HTML file, only if your server is configured to allow this. If it's not possible, you can still use another extension.
So, the more correct way is to remap the existed error page, such like this:
RewriteCond %{REQUEST_URI} !^/index\.php
RewriteRule ^(.*) /403.shtml
But anyway, what are you trying to do?

How do I hide actual directories using mod_rewrite?

I am hosting a couple of domains of the same wordpress installation, now I'd like to have a per-domain folder for some various files I need to put up there.
Essentially I want to map like this:
URL Path
webbfarbror.se/f/* _files/webbfarbror.se/*
grapefrukt.com/f/* _files/grapefrukt.com/*
This little snippet does the job nicely and the RewriteCond let's me enable and disable this on a per domain basis.
ReWriteCond %{HTTP_HOST} webbfarbror.se
ReWriteRule ^f/(.*)$ _files/%{HTTP_HOST}/$1 [L]
However, a file at say, http://grapefrukt.com/f/awesome.jpg is also accessible at it's "real" URL http://grapefrukt.com/_files/grapefrukt.com/awesome.jpg
All my attempts result in infinite redirects back and forth.
How do I disable access through the latter URL?
You can examine the original request as it was sent to the server, which is available as %{THE_REQUEST}. Checking for the /_files/ prefix indicates that the request was of the latter type, and you can then redirect to the appropriate format:
RewriteCond %{THE_REQUEST} ^[A-Z]+\s/_files/
RewriteRule ^_files/[^/]+/(.*)$ http://%{HTTP_HOST}/f/$1 [R=301,L]

.htaccess mod_rewrite issue

Almost in any project I work on, some issues with .htaccess occur. I usually just find the easiest solution and leave it because I don't have any knowledge or understanding for Apache, servers etc. But this time I thought I would ask you guys.
This is the files and folders in my (simplified) setup:
/modrewrite-test
.htaccess
/config
/inc
/lib
/public_html
.htaccess
/cms
/navigation
index.php
edit.php
/pages
index.php
edit.php
login.php
page.php
The "config", "inc" and "lib" folders are meant to be "hidden" from the root of the website. I try to accomplish this by making a .htaccess-file in the root that redirects the user to "public_html". The .htacess-file contains this:
RewriteEngine On
RewriteRule (.*) public_html/$1
This works perfect. If I type "http://localhost/modrewrite-test/login.php" in my browser, I end up in public_html/login.php which is my intention. So this works fine. The .htaccess-file in "public_html" contains this:
RewriteEngine On
# Root
RewriteRule ^$ page.php [L]
# Login
RewriteRule ^(admin)|(login)\/?$ login.php [L]
# Page (if not a file/directory)
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ page.php?url=$1 [L]
The first rewrite just redirects me to public_html/page.php if I try to reach "http://localhost/modrewrite-test/". The next rewrite is just for the convenience of users trying to log in - so if they try to reach "http://localhost/modrewrite-test/admin" or "http://localhost/modrewrite-test/login" they will end up at the login.php-file. The third and last rewrite handles the rest of the requests. If I try to reach "http://localhost/modrewrite-test/bla/bla/bla" it will just redirect me to public_html/page.php (with the 'url' GET-variable set) instead of finding a folder called "la", containing a folder named "bla" and etc.
All of these things work perfect but a minor issues occurs when I for instance try to reach "http://localhost/modrewrite-test/cms/navigation" without a slash at the end of the URL. When I try to reach that page the browser is somehow redirected to "http://localhost/modrewrite-test/public_html/cms/navigation/". The correct page is shown but why does it get redirected and add the "public_html" part in the URL? The desired behavior is that the URL stays intact and that the page public_html/cms/navigation/index.php is shown.
The files and folders in the (simplified) can be found at http://highbars.com/modrewrite-test.zip
I ran into the same problem with "strange" redirects when trying to access existing directory without slash at end. In my case this redirection was done by mod_dir Apache module. To disable redirection I used DirectorySlash directive. Try putting in .htaccess files following string:
DirectorySlash Off
RewriteBase may help. Try this in public_html/.htaccess:
RewriteEngine On
RewriteBase /
Add the following to /modrewrite-test/.htaccess:
RewriteBase /modrewrite-test
Just to be on the safe side, I'd add the same rule also to /modrewrite-test/public_html/.htaccess. I found that having RewriteBase always set prevents a lot of potential problems in the future. This however means that you might need to update the values if you change the URI structure of your site.
Update:
I don't think that this is possible with your current folder structure. I believe that the problem is that existing subdirectories prevent rewrite rules from firing. Note the behavior please - everything works fine while you are working with non-existent files and directories, thanks to these two conditions:
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
However if you try to open any index file from an existing subdirectory, you get redirected to .../public_html/.... Since you can properly open /modrewrite-test/cms/navigation/edit.php, I can only assume that the request is being overwritten by some Apache core directive, which adds slashes at end of folder URLs. Notice that everything works fine if you have an ending-slash at each URL (i.e. the Apache core directory does not need to "correct" your URL, thus everything gets rewritten by your own rewrite rules).
Suggested solution (unless anyone can advise better):
Change /modrewrite-test/public_html/.htaccess as follows:
RewriteEngine On
RewriteBase /modrewrite-test
# Page (if not a file/directory)
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ page.php?url=$1 [L]
Then Remove all PHP files from subfolders and use the Front Controller pattern, i.e. route all requests through your main page.php file and do not delegate anything down below.
You can then use the Factory pattern to initiate individual UIs (i.e. navigation/edit.php) directly from your main page.php file based on contents of $_GET['url'] (make sure to properly sanitize that).
Update #2:
This other post on StackOverflow advises on project structure used by Zend Framework - it essentially shows the approach which I suggested above. It is a valuable information asset regardless if you use Zend Framework or not.

Apache Rewrite: directory tree to subdomain directory

I have a web application that has one set of files used by 50+ clients and all the configuration for each site comes from a config.php file in their respective directories. This is accomplished with PHP parsing the URL. All this works fine, just having an issue with custom uploaded documents the client can do and are located in
/var/www/sites/user1/cache
There can be multiple subdirs. So when requesting
http://user1.site.com/cache/subdir1/image.jpg
it needs to be read from
/var/www/sites/user1/cache/subdir1/image.jpg
The client is allowed to upload any file type, so I just need the rewrite to take any /cache requests, then grab the subdomain and point to proper directory.
Came up with this, but am still getting an invalid page
RewriteEngine On
RewriteCond %{HTTP_HOST} ^([^\.]+)\.site\.com$
RewriteRule ^cache/(.*)$ /sites/%1/cache/$1 [L]
Any help is appreciated.
If I read the RewriteRule documentation correctly, the L flag on its own would generate an internal redirection, meaning that the substitution would be interpreted as a local file system path.
Try using the complete path:
RewriteRule ^cache/(.*)$ /var/www/sites/%1/cache/$1 [L]
or do an external redirection (using HTTP return status "302 MOVED TEMPORARILY"), to let the user's browser re-send the request with the new path:
RewriteRule ^cache/(.*)$ /sites/%1/cache/$1 [L,R]
The /var/www/ is where the files are on the filesystem. I was routing based on the document root so I didn't need to put that there. But I realized I was missing the leading forward slash on the /cache/. Though your answer wasn't really what I was looking for, it made me see what I was missing. Thanks.
RewriteEngine On
RewriteCond %{HTTP_HOST} ^([^\.]+)\.site\.com$
RewriteRule ^/cache/(.*)$ /sites/%1/cache/$1 [L]