How to block files from access by URL - .htaccess

i have subpage like
mypage.com/subpage
But that is only alias and all files are in/data/subpage. And only file needed to be accessed by user himself is index.php and all other files are imported by index itself, depending on attributes (GET, sessions etc.)
I want this:
Let user to access index.php using /subpage but not /data/subpage
Do not let user directly access anything in /data/subpage and its subfolders
still let index.php to access those files.
I hope I wrote it understandably.
Thank you for your help
EDIT: My current .htaccess (located in root)
RewriteEngine On
RewriteRule ^subpage$ /data/subpage/index.php [L]
RewriteRule ^subpage/(?:([^/]+)/?|)(?:([^/]+)/?|)$ /data/subpage/index.php?section=$1&subsection=$2 [L]
RewriteRule ^edit/subpage/?(?:([^/]+)/?|)(?:([^/]+)/?|)$ /data/subpage/index.php?edit=true&section=$1&subsection=$2 [L]

Try:
RewriteCond %{THE_REQUEST} \ /+data/subpage/
RewriteRule ^ - [L,R=404]
so that any direct requests for /data/subpage/ results in a 404. You can replace R=404 with F if you would rather it result in a "403".
EDIT:
It's kinda right, thank you. I, as a viewer, can't access those files but my page also cant access it (for ex. images). Is there any way to do it?
This isn't your page accessing those files, it's your page telling the browser to access them. That means the only way you're going to know that the page told the browser to access them is to check the referer. Unfortunately, the referer can be trivially forged so this is no guarantee that people can't get to all your files.
RewriteCond %{THE_REQUEST} \ /+data/subpage/
RewriteCond %{HTTP_REFERER} !^http://yourdomain.com/subpage/(index\.php)?
RewriteRule ^ - [L,R=404]

Related

mod-rewrite redirect but prevent direct access

I want to redirect all content to:
www.example.com/public/...
but prevent direct access to
www.example.com/public/file1/
www.example.com/public/file2/
etc
The final URL should be:
www.example.com/file1/
I've tried this for redirecting and it works - but I dont know how to prevent direct access:
ReWriteCond %{REQUEST_URI} !/public/
RewriteRule ^(.*) public/$1 [L]
After spending an inordinate amount of time trying to solve this problem, I found that the solution lies with the under-documented REDIRECT_STATUS environment variable.
Add this to the beginning of your top-level /.htaccess code, and also to any .htaccess files you have under it (e.g. /public/.htaccess):
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{ENV:REDIRECT_STATUS} !=200
RewriteRule ^ /public%{REQUEST_URI} [L]
</IfModule>
Now, if the user requests example.com/file1 then they are served the file at /public/file1. However, if they request example.com/public/file1 directly then the server will attempt to serve the file at /public/public/file1, which will fail (unless you happen to have a file at that location).
IMPORTANT:
You need to add those lines to all .htaccess files, not just the top-level one in the web root, because if you have any .htaccess files below the web root (e.g. /public/.htaccess) then these will override the top-level .htaccess and users will again be able to access files in /public directly.
Note about variables and redirects:
Performing a redirect (or a rewrite) causes the whole process to start again with the new URI, so any variables that you set before the redirect will no longer be set afterwards. This is done deliberately, because usually you do not want the final result to depend on how you got there (i.e. whether it was via a direct request or via a redirect).
However, for those special occasions where you do want to know how you got to a particular URI, you can use REDIRECT_STATUS. Also, any environment variables set before the redirect (e.g. with SetEnvIf) will still be available after the redirect, but with REDIRECT_ prefixed to the name of the variable (so MY_VAR becomes REDIRECT_MY_VAR).
Maybe you should clarify what's the expected behaviour when user tries to reach the real URL:
www.example.com/public/file1/
If by prevent you mean forbid, you could add a rule to respond with a 403
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{REQUEST_URI} !/public/
RewriteRule ^(.*)$ /public/$1 [L]
RewriteCond %{REQUEST_URI} /public/
RewriteRule ^(.*)$ / [R=403,L]
</IfModule>
Update: The solution above doesn't work!
I realized my previous solution always throws the 403 so it's worthless. Actually, this is kinda tricky because the redirection itself really contains /public/ in the URL.
The solution that really worked for me is to append a secret query string to the redirection and check for this value on URL's containing /public/:
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{REQUEST_URI} !/public/
RewriteRule ^(.*)$ /public/$1?token=SECRET_TOKEN [L]
RewriteCond %{REQUEST_URI} /public/
RewriteCond %{QUERY_STRING} !token=SECRET_TOKEN
RewriteRule ^(.*)$ / [R=403,NC,L]
</IfModule>
This way www.example.com/file1/ will show file1, but www.example.com/public/file1/ will throw a 403 Forbidden error response.
Concerns about security of this SECRET_TOKEN are discussed here: How secure is to append a secret token as query string in a htaccess rewrite rule?
If your URL's are expected to have it's own query string, like www.example.com/file1/?param=value be sure to add the flag QSA.
RewriteRule ^(.*)$ /public/$1?token=SECRET_TOKEN [QSA,L]

Block a specific file

I want to use mod_rewrite to block access to a file.
Let's say index.html as an example.
I know you can use FileMatch but I want to use mod_rewrite to do this.
I tried doing something like this:
RewriteEngine On
RewriteCond %(REQUEST_URI} !^/index\.html$
RewriteRule (.*) - [L]
But that doesn't work, how to I archive that?
You can use the F flag to deny access to a given file:
RewriteEngine On
RewriteRule ^index.html$ - [F]
Deny access to any file that ends with .pdf:
RewriteRule \.pdf$ - [F]
If your file used to exist there are a couple of options. Rather than saying "Access Denied" to the browser, search engine, or user. If you removed the file and have no other file to takes it's place then you can respond with a 410 Gone error by using the G flag.
RewriteRule ^yourfile.html$ - [G,L]
If it's in some directory, then you have to include the directory as well, but since we're using .htaccess we won't need the preceding slash.
RewriteRule ^some-directory/yourfile.html$ - [G,L]
If you've moved the file, then you can respond with a 301 Redirect response to let the users, search engines, and everyone else know that the file has a new permanent location
RewriteRule ^old-directory/yourfile.html$ new-directory/yourfile.html [R=301,L]
If you want to tell people that the file still exists but they can not access it because it's now privileged, then you can make the request for the file respond with 403 forbidden.
RewriteRule ^some-directory/yourfile.html$ - [F,L]
You can learn more about the various rewrite flags on this page.

.htaccess URL rewrite only rerwites one page

I'm rerwiting a URL to point to a different URL under the hood. But it seems like all the other files in different directories referenced by index.php (e.g. css files, JS files, etc) do not get redirected. How can I accomplish this?
I have
RewriteEngine On
RewriteCond %{REQUEST_URI} ^/test($|/)
RewriteRule .*$ ../index.php?orgid=4 [L]
I found the answer is
RewriteRule ^(test)(.*)/?$ index.php?orgid=4 [L]
In the browser, this will show as example.com/test, while under the hood the url is actually example.com/index.php?orgid=4

Use htaccess to redirect root but still have directory listing accessible with a backdoor

What I thought I was trying to do was genius, but it seems to not work properly.
I have a public subdomain with temp files on it. I don't want people to be able to see all the files listed when they visit it. I don't want to password protect it because that will mess up several scripts when fetching files off the server, and I don't want a blank index.html there to stop listing because I want to be able to see the listing.
So my stroke of genius was to have a .htaccess file like so:
RewriteEngine On
RewriteCond %{REQUEST_URI} !/#dir
RewriteCond %{REQUEST_URI} !/?show=dir
RewriteRule ^$ http://example.com/ [nc]
My theory was that visiting files.example.com would redirect to example.com but visiting files.example.com/?show=dir or files.example.com/#dir would not; and obviously since ?show=dir does nothing it would list all my files as normal.
My RewriteConditions have no effect though.
Is this possible?
First, you can't match against URL fragments (the #dir part) because that doesn't ever get sent to the server. It's a client side only thing.
Second, you can't match against the query string (the ?show=dir part) in the %{REQUEST_URI} variable, you need to use %{QUERY_STRING} instead.
So try:
RewriteEngine On
RewriteCond %{QUERY_STRING} !^show=dir$
RewriteRule ^$ http://example.com/ [nc]

Tricky: Remap url but stay on the same url internally

Need your help. Just spend many ours on this htaccess problem and still don't have a clue how to manage this.
I have many http://www.example.com/menu-alias/foo links on my company's website which should get redirected to http://www.example.com/foo.
This alone shouldn't be the hard part but listen up... the tricky part follows.
I don't manage to get the site (Joomla 1.5) working without the 'menu-alias' this means that all http://www.example.com/foo should get internally mapped to http://www.example.com/menu-alias/foo. So that the user still has http://www.example.com/foo in his browser's address bar.
To make it even more complicated i have to 301 redirect the old menu-alias/foo links to /foo.
Can some htaccess guru help me out? Is this even possible?
You can try adding these rules in the htaccess file in your document root (or vhost config):
RewriteEngine On
# externally redirect requests that have "menu-alias"
RewriteCond %{THE_REQUEST} /menu-alias/([^\ \?]+)
RewriteRule ^ /%1 [L,R=301]
# internally rewrite requests back to menu-alias
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} !^/menu-alias/
RewriteRule ^/?(.*)$ /menu-alias/$1 [L]
Couple of potential problems:
Joomla may be looking for the original un-rewritten request in $_SERVER, if so, the rewrite won't work.
The rule to add the /menu-alias/ back into the URI does so blindly rewrites all requests that don't point to an existing resource. This means "virtual" paths that Joomla may handle will get a "menu-alias" appended to the front.

Resources