Block a specific file - .htaccess

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.

Related

htaccess directory management

im going to ask a really simple question. i dont want my link to show this when i run my page :
http://localhost/example/assets/gallery.php
what i want is :
http://localhost/example/assets/
so how to do it in .htaccess file ?
i would really appreciate it if you can help because im so confused after reading forums .
my htaccess is like this right now but you know it only helps to remove extension :
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^([^\.]+)$ $1.php [NC,L]
How to make assets/gallery.php -> assets/
In the assets folder make a .htaccess file
Paste in this code :
DirectoryIndex gallery.php
This code changes the Directory Index (like a index.php file) to the gallery.php file meaning gallery.php is now like the index.php file.
The DirectoryIndex method that #RyanTheGhost suggests in his answer should have worked for the specific example you posted (where you request a directory and are serving a file from within that directory). However, the mod_rewrite directives you currently have in the document root1 will conflict with any requests for directories2 (although the DirectoryIndex should take priority).
However, the DirectoryIndex method is not very practical if you have many such files. And if you are not requesting a directory then this method naturally won't work anyway.
You could instead rewrite the URL using mod_rewrite in your existing .htaccess file, before your current directives.
1 I'm assuming your .htaccess file is in the document root.
For example:
# Rewrite "/example/assets/" to "/example/assets/gallery.php"
RewriteRule ^example/assets/$ example/assets/gallery.php [L]
Or, to avoid repitition:
# Rewrite "/example/assets/" to "/example/assets/gallery.php"
RewriteRule ^example/assets/$ $0gallery.php [L]
Where the $0 backreference contains the entire URL-path that is matched by the RewriteRule pattern. ie. example/assets/ in this case. NB: There is no slash prefix on the RewriteRule pattern or the substitution string.
Note that since you are requesting a directory (ie. /example/assets/) you need to ensure there is no DirectoryIndex document in that directory (eg. index.html or index.php), otherwise this will be served (by mod_dir) instead, overriding your internal rewrite above.
2 Your current directives that append the .php extension are arguably incorrect:
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^([^\.]+)$ $1.php [NC,L]
This rule appends the .php extension to any request that does not map to a physical file, even if the file with a .php extension does not exist either. This can result in the incorrect URL being reported back to the user in the 404 error document (depending on how this is implemented). For example, the default Apache 404 error document will report that /foo.php does not exist, when the user requested /foo.
This rule will also rewrite directories (since they are "not files") which will result in a 404 (as opposed to a 403 or directory listing, if enabled). Although a DirectoryIndex document will override this.
Additionally, the NC flag is superfluous and there is no need to backslash-escape the literal dot inside a character class.
You could instead check that the corresponding .php file exists before rewriting, instead of checking that the requested URL does not map to a file.
For example:
RewriteCond %{DOCUMENT_ROOT}/$1.php -f
RewriteRule ^([^.]+)$ $1.php [L]
The request is now only rewritten when the corresponding .php file exists, which naturally avoids any conflicts with directories.

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]

How to block files from access by URL

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]

.htaccess rewriterule - check for referrer, if wrong referrer send to a specific URL, if right, allow directory to be read

I have a folder on my site (domain.com/protect) I want to limit to only one referrer (otherdomain.com/subfolder).
Deny for all others, allow only if coming from that URL.
If not coming from that URL, then redirect the visitor over to otherdomain.com/login instead.
How would I write that out in .htaccess rewrite rules?
In the htaccess file in your /protect directory, add these rules:
RewriteEngine On
RewriteCond %{HTTP_REFERER} !otherdomain\.com/subfolder
RewriteRule ^ - [L,F]
The condition checks that the referer doesn't contain: otherdomain.com/subfolder, and if it doesn't, then whatever the request is (inside the /protect directory) will result in a 403 Forbidden.
Alternatively, you can put these rules in the htaccess file in your document root if you would rather keep everything in once place:
RewriteEngine On
RewriteCond %{HTTP_REFERER} !otherdomain\.com/subfolder
RewriteRule ^/?protect/? - [L,F]

How can I get non existant files mapped correctly in .htaccess?

Duplicate:
How to rewrite non existant files to
‘default’ files?
(.htaccess)
How would I "rewrite" to a location if a file doesn't exist? I don't want to use a 404 redirect, but an actual rewrite.
So for example, let's say it is a directory with images. If the image isn't found, then it rewrites to a default image?
I.e.,
images/1.jpg
images/2.jpg
images/default.jpg
if someone tried to access "website.com/images/3.jpg",
since that doesn't exist, I want it to go to:
"website.com/images/default.jpg"
This was a previous "posted" solution, but didn't quite work:
RewriteCond %{REQUEST_FILENAME} !-f [NC]
RewriteRule /images/.* /images/error.jpg [L]
It still doesn't "get" the right image (just goes as a regular 404 request).
RewriteCond %{REQUEST_FILENAME} !-f [NC]
RewriteRule ^images/.* /images/error.jpg [L]
Obviously this only redirects if missing file is under /images/... but you can easily modify it for your own needs
Well, your previous posted solution is on the right track, but there's some slight craziness with it. Try this:
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule images/.* /images/default.jpg [L]
You should better send a 404 status code if the file really doesn’t exist rather than just a substitute with a status code other than 404. Otherwise the URL will be handled as valid.
So in your case I recommend you to set the ErrorDocument of the images directory to your default image:
<Directory "/path/to/your/images/">
ErrorDocument 404 /images/default.jpg
</Directory>
But note that the <Directory> block is only available in the server or virtual host configuration context and not the per-directory context (thus .htaccess).
If you cannot use the above, you could use a custom script as your custom error document to check what URL has been requested (see Request_URI environment variable) and send the default image if necessary. The ErrorDocument directive then should look like this:
ErrorDocument 404 /your-error-404.script
re-write your 404 document for your images folder:
(In your .htaccess file in your images folder)
ErrorDocument 404 default.jpg

Resources