After reading this article I immediately checked my application and found that it was subject to this issue. I started worrying and testing out how to mitigate this issue and protect my application.
However, after calming down, I started looking for the cause of this issue, and finally I came to the conclusion that the problem is not from PHP, or Apache, but only in the content of the `.htaccess' file.
Here are my observation on this issue and the working of Apache with mod_php5.
- The problem is not only with Zend Server as I replicated the problem with a standard PHP 5.3 and the same `.htaccess'.
Why is Apache granting access to "GETS" requests without authentication ?
The .htaccess specify that the "require valid-user" only applies to "GET" and "POST" requests. So, a "GETS" request is not subject to the "require valid-user".
So the request is processed without asking for authentication.
Why Apache does not reject the invalid "GETS" request ?
Apache does not send a "invalid method" HTTP error message because the ressource pointed by the URL is handled by mod_php5 (AddHandler php5-script .php), so it assumes that mod_php5 will know what to do with a "GETS" requests.
So, it passes the request to mod_php5.
This is convenient for implementing new HTTP method like DAV methods in PHP without Apache knowing in advance the full set of method for this protocol.
Why is PHP treating the request as a "GET" request ?
From the source code of PHP 5.3 (main/SAPI.C:sapi_activate()) we see that PHP first check if the request is a "HEAD" (special treatment "only headers") or "POST" (special treatment for decoding the POST data), then anything else is handled to the script.
This is also convenient for handling new HTTP methods (e.g. DAV PROPFIND) from PHP scripts.
So, mod_php5 run the scripts and assumes that the script will know what to do with a "GETS" method.
The script does not check which method was used, so it print out his result on STDOUT and that gives a "HTTP 200 OK" response to the client.
After these observations, I come to the conclusion that this behaviour is normal, and that the real problem lies in the `.htaccess' which only protects "GET" and "POST" request, missing the fact that other methods can pass and be used to trigger the execution of the PHP script.
One solution is to deny acces to anything that is not "GET" or "POST" with a <LimitExcept />:
AuthUserFile .htpasswd AuthName "Protected Area" AuthType Basic <Limit GET POST> require valid-user </Limit> <LimitExcept GET POST> Order Allow,Deny Deny from all </LimitExcept>
Another one would be to check in the PHP scripts that the $PHP_AUTH_USER variable is set, which will indicate that the HTTP Basic auth as been successfully completed.
Or check $_SERVER["REQUEST_METHOD"], and return an error message if the method is not "GET" or "POST".