Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Always return a 404 when you decide to return a 403

There are several questions already posted here about returning a 404 instead of a 403 in special cases (e.g., .ht* files or a certain directory), but I can't figure out how to simply replace all 403 responses ("Okay, it exists, but you still have to find a way in") with 404s ("Sorry, never heard of it"). I'm hoping that there is a simple solution that won't require updating regexes or other bits of the .htaccess to match site changes, just a simple directive: "whenever you decide to return a 403, return a 404 instead" that applies to the whole site, regardless of configuration changes.

Then, if the top level .htaccess contains "Options -Indexes", and any given directory contains no index.html (or equiv), the bare directory URL will return 404, but if I ever add an index.html to that directory, the same bare directory URL will return the index.html, with no updates needed to any .htaccess file.

I don't even care if, in the event I ever password a directory, a bad password returns a 404 (because of the 404 -> 403 mapping). In that case, I'm not hiding anything by returning a 404, but it causes no harm either. If there's a way to UNDO the general 403->404 mapping for special cases (rather than DO it for special cases), though, that could be even more useful.

Of course, if I'm overlooking something, please set me straight.

EDIT: Drat. I was trying to write a good quality question here, but my description of the behavior of "Options -Indexes" in the second paragraph turns out to be wrong. Without that line a bare directory URL shows "index.html" if exists in the directory; otherwise, it reveals the contents of the directory. (That forwarding of /dir to /dir/index.html if index.html exists is the default setup of the Web host, unless I'm mistaken.) Adding the "Options -Indexes" line stops it airing my laundry in public (returning a 403, not 404, but still better than exposing the dir contents), but now the bare directory URL returns a 403 even if index.html exists.

I wish a bare dir URL "mysite.com/mydir" displayed /mydir/index.html if it existed and "404" if it didn't, but clearly there's more to it than just replacing the 403s with 404s.

like image 345
Glen Avatar asked May 09 '12 04:05

Glen


People also ask

Is 403 and 404 the same?

The three status codes that felt the most appropriate are: 401 - Unauthorized. 403 - Forbidden. 404 - Not Found.

What is 403 and 404 error?

The 404 status code can also be used in 403 scenarios, when the server does not want to send back the reason why it is refusing to serve the request. A good example is when the server senses some kind of an attack, which might be a brute force attack.

Is it correct to return 404 when a rest resource is not found?

Something goes wrong, the resource you need to be there is not found. If it would be an endpoint to fetch the list of products that expired yesterday (for instance) but there are none, then a 404 would not be correct since you cannot expect to always have products expire every day.

What do you understand by 404 and 500 error code?

1. 500 Internal Server Error - The server encountered an unexpected condition which prevented it from fulfilling the request. 2. 404 Not Found - The server has not found anything matching the Request-URI.


1 Answers

To complete one of the better answers here (as mentioned by @WebChemist and @JennyD), a good way to solve this is to return 404 Not Found from the document you use to handle 403 errors. Personally I do something like the following:

.htaccess in web root (relevant excerpt):

ErrorDocument 400 /http-errors.php
ErrorDocument 403 /http-errors.php
ErrorDocument 404 /http-errors.php

http-errors.php in web root (condensed working example):

<?php

$status = $_SERVER['REDIRECT_STATUS'];
// If it's a 403, just bump it up to a 404
if ( $status == 403 ) $status++;

$codes = array(
  400 => array( '400 Bad Request', 'The request cannot be fulfilled due to...' ),
  404 => array( '404 Not Found', 'The resource you requested was not found...' ),
  500 => array( '500 Internal Server Error', 'The request was unsuccessful...' )
);

$title = $codes[$status][0];
$message = $codes[$status][1];

header( $_SERVER['SERVER_PROTOCOL'] . ' ' . $title );
echo "<h1>$title</h1>\n<p>$message</p>";
like image 106
Marcel Avatar answered Sep 19 '22 04:09

Marcel