30

Is there a way how I can configure the Apache web server to return a 404 (not found) error code instead of 403 (forbidden) for some specific directories which I want to disallow to be accessed?

I found some solutions suggesting the use of mod_rewrite, like e.g.

RewriteEngine On
RewriteRule ^.*$ /404 [L]

As the purpose of sending 404 instead of 403 is to obfuscate the directory structure, this solution is too revealing, because it redirects to some different location which makes it obvious that the directory originally accessed does in fact exist.

fuenfundachtzig
  • 7,952
  • 13
  • 62
  • 87
  • Does [this question](http://stackoverflow.com/questions/548156/problem-redirecting-403-forbidden-to-404-not-found) solve your problem? – Jeremy Stein Sep 28 '09 at 15:06
  • I didn't consider this question when I first saw it (too confusing), but after a second glance I found the line I've been looking for, thanks. – fuenfundachtzig Sep 28 '09 at 15:34

4 Answers4

30

RedirectMatch as in e.g.

RedirectMatch 404 /\.

does the trick, it prohibits access to all files or directories starting with a dot, giving a "404 Not Found" error.

From the Apache manual: "The Redirect[Match] directive maps an old URL into a new one by asking the client to refetch the resource at the new location." By default, Redirect sends a 302 return code, but it can also return other status codes as shown above.

fuenfundachtzig
  • 7,952
  • 13
  • 62
  • 87
  • 4
    +1, but to match a single dot anywhere in the url path, do we really need the quotes and the dot-star? I.e., can't we just do `RedirectMatch 404 /\.` instead of `RedirectMatch 404 ".*\/\..*"` ? – zx81 Jun 20 '14 at 21:13
  • @fuenfundachtzig it returns 403 for ".git/.htaccess"and ".git/.php" instead of 404 – Awaaaaarghhh Apr 13 '20 at 23:57
  • @Awaaaaarghhh, that's likely because you have a `FilesMatch` directive in your apache configuration that takes precedence. A custom `ErrorDocument` for 403 as suggested in Tomer's answer would cover this case, too, but requires `php`. – fuenfundachtzig Apr 16 '20 at 20:43
  • @fuenfundachtzig `but requires php`, no, why php?! - you can use also static html documents like "my404error.html" for your custom ErrorDocument! `that's likely because you have a FilesMatch dir`, no, i tested it without `RedirectMatch`. anyway thank you! :) I was able to fix everything, now all requests return 404 error: https://stackoverflow.com/a/61199481/4224741 (I used `FilesMatch`). I tested a lot & read apache docs, but was not able to use `RedirectMatch` properly in that specific case. – Awaaaaarghhh Apr 16 '20 at 21:26
  • Because with `html` you won't be able to change 403 to 404. – fuenfundachtzig Apr 17 '20 at 07:38
10

You can make something like this:

.htaccess

ErrorDocument 403 /error/404.php

404.php

<?php
$status = $_SERVER['REDIRECT_STATUS'] = 404;
header( $_SERVER['SERVER_PROTOCOL'] . ' ' . $status);
?>

404 Error
Tomer
  • 3,149
  • 23
  • 26
  • 4
    *Why is this not upvoted enough?* I used this solution. It's very straightforward. However, since I have PHP >= 5.4.0, I simply used `` at the top of the `404.php` page. This way I can use `ErrorDocument *** any code *** /error/404.php` and they will all become `404` in the HTTP header. – ADTC Mar 27 '16 at 07:56
  • What if I want to send all requests to a unique index.php front controller script and have it decide if 404.php should be executed? – tonix May 07 '16 at 21:22
  • 3
    @ADTC, it's not relevant to the question, which was how to ask Apache to do this, not PHP. – Chris Cogdon Feb 28 '17 at 18:36
  • @ChrisCogdon How to ask Apache to do this > this is exactly what `.htaccess`, an Apache-readable file, does. So in the end, this answer is still asking Apache to do this. Apache executes the `404.php` file when there is a 403 error. PHP parses the file and sends the output _through Apache web server_ to the browser. Where's the irrelevancy in this? – ADTC Mar 03 '17 at 02:27
  • @tonix you simply need to redirect all the error codes to `index.php` and write the PHP script in it to do the needful (check and decide if 404, then include 404.php otherwise include some other content). – ADTC Mar 03 '17 at 02:31
6

After having the same problem, I ended up with the following .htaccess file

Options -Indexes
RewriteCond %{HTTP_HOST} ^(www\.)?mydomain.com [NC]
RewriteRule ^(.*)/$ - [R=404,NC]

The 1st and 3rd line ensure that you can't list the folder content, and if you do it you will receive a 404 error. The RewriteCond directive ensures that this rewrite rule only applies to main domain. Since I have several subdomains, without the rewritecond, accessing www.mydomain.com/subdomain was also returning a 404, which was not what I intended.

jff
  • 476
  • 5
  • 10
  • This works well for me. Just one issue is the way `Options -Indexes` works: /img/ (which doesn't exist) correctly returned a 404, but /img/ (which does exist and I want access to, but not a directory listing for) returned a 403. So, what I did was remove `Options -Indexes` and just make sure the regexes (that specify allowed files) never match just a directory name. – Darren Cook Apr 14 '14 at 00:27
  • *That is not a subdomain, but a sub-site..., could be bypassed by RewriteCond for directory check (... -d ...)... – jave.web Apr 16 '16 at 12:28
1

In my opinion making this task in .htaccess is quite ugly solution.

It is possible to make it in apache configuration. Take a look:

Add to your apache config:

ErrorDocument 403 /404

Then restart apache:

service apache2 restart

That is all.

Adam Kozlowski
  • 5,606
  • 2
  • 32
  • 51