Is it possible that REMOTE_ADDR could be blank? - php

As far as I'm aware, the webserver (Apache/Nginx) provides the ($_SERVER['REMOTE_ADDR']) based on the claimed location of the requesting user agent. So I understand they can be lying, but is it possible that this value could be blank? Would the network interface or webserver even accept a request without a correctly formed IP?
http://php.net/manual/en/reserved.variables.server.php

It is theoretically possible, as the matter is up to the http server or at least the corresponding PHP SAPI.
In practice, I haven't encountered such a situation, except with the CLI SAPI.
EDIT: For Apache, it would seem this is always set, as ap_add_common_vars always adds it to the table that ends up being read by the Apache module PHP SAPI (disclaimer: I have very limited knowledge of Apache internals).
If using PHP in a CGI environment, the specification in RFC 3875 seems to guarantee the existence of this variable:
4.1.8. REMOTE_ADDR
The REMOTE_ADDR variable MUST be set to the network address of the
client sending the request to the server.

Yes. I currently see values of "unknown" in my logs of Apache-behind-Nginx, for what looks like a normal request/response sequence in the logs. I believe this is possible because mod_extract_forwarded is modifying the request to reset REMOTE_ADDR based on data in the X-Forwarded-For header. So, the original REMOTE_ADDR value was likely valid, but as part of passing through our reverse proxy and Apache, REMOTE_ADDR appears invalid by the time it arrives at the application.
If you have installed Perl's libwww-perl, you can test this situation like this (changing example.com to be your own domain or application):
HEAD -H 'X-Forwarded-For: ' -sSe http://www.example.com/
HEAD -H 'X-Forwarded-For: HIMOM' -sSe http://www.example.com/
HEAD -H 'X-Forwarded-For: <iframe src=http://example.com>' -sSe http://www.example.com/
( You can also use any other tool that allows you to handcraft HTTP requests with custom request headers. )
Now, go check your access logs to see what values they logged, and check your applications to see how they handled the bad input. `

Well, it's reserved but writable. I've seen badly written apps that were scribbling all over the superglobals - could the script be overwriting it, e.g. with $_SERVER['REMOTE_ADDR'] = '';?
Other than that, even if the request were proxied, there should be the address of the proxy - could it be some sort of internal-rewrite module messing with it (mod_rewrite allows internal redirects, not sure if it affects this)?

It shouldn't be blank, and nothing can't connect to your web service. Whatever's connecting must have an IP address to send and receive data. Whether that IP address can be trusted is a different matter.

Related

How to read the host name from a request URI in PHP?

For the router, I wanted to get the host name from the URI upon a server request. I know that I need to read it from the $_SERVER variable. But it seems that in the $_SERVER array there are multiple entries (at least two) for the host name.
Could you please tell me which value should I choose to read - the most reliable one?
For example, when I have an URI like this:
http://local.mvc/mycontroller/myaction
the $_SERVER array will have:
[HTTP_HOST] => local.mvc
[SERVER_NAME] => local.mvc
I need to obtain the value local.mvc.
Thank you for your time.
SERVER_NAME is the name assigned to the given server in its configuration (be it i.e. apache.conf file and its ServerName directive or similar for other software), while HTTP_HOST value is obtained from the headers of HTTP request that comes from client (web browser usually). These two might differ if your server servers multiple domains (like shared server / virtual server hosting). Depending on the use case you may want to use either of these, however HTTP_HOST seems like better choice as it is always tells what user wanted to reach.
the $_SERVER variable has 'REQUEST_URI'.
just var_dump the server variable, and is should be there (or look at the documentation)
If you're using PHP5 or PHP7, try php_uname
To get the host name:
php_uname("n");

How to prevent apache from sending connection close header <s>on 304 answers</s>

I have the following setup:
Some files are dynamically generated dependent on some (only a few) session parameters. Since they have not a great diversity, i allow caching in proxys/browsers. The files get an etag on their way, and the reaction of the whole web application at first glance seems correct: Files served in correct dependence from session situations, traffic saved.
And then this erroneous behavior:
But at closer inspection, i found that in his answer in case of a 304 for those dynamically generated files, apache wrongly sends a "Connection: close" Header instead of the normally sent "Connection: KeepAlive". What he should do is: Simply do not manipulate anything concerning "connection".
I cannot find any point where to pinpoint the cause of this behavior: Nowhere in the apache config files is anything written except one single line in one single file where it is instructed to send a keepalive - which it does - as long as it does not send a 304 response for a dynamically generated file. Nowhere in PHP do i instruct that guy to send anything other than keepalives (and the latter only to try to counter the connection:close).
The apache does not do this when it serves "normal" (non-dynamic) files (with 304 answers). So in some way i assume that maybe the PHP kernel is the one who interferes here without permission or being asked. But then, an added "Header set Connection 'Keep-Alive'" in the apache config, which i too added to counter the closing of the connection, does not work, too. Normally, when you put such a header set rule (not of "early" type) in the apache config, this rules takes action AFTER finalization of any subordered work on the requested document (thus AFTER finalization of the PHP output). But in my case, nothing happens - well: in case of a 304 response. In all other cases, everything works normal and correct.
Since there do some other files go over the line at a page request, i would appreciate to get the apache rid of those connection-closures.
Is there anybody who has an idea what to do with this behavior?
P.S.: One day (and a good sleep) later, things are clearing:
The culprit in this case was a shortsightedly (on my behalf) copied example snippet, which had "HTTP/1.>>>0<<< 304" (the Null!) in it.
This protocol version number gets (correctly) post-processed by apache (after everything otherwise - including any apache modules work - got finalized), in that it decides not to send a "Connection: Keep-Alive" over the wire, since that feature didn't exist in version HTTP/1.0.
The problem in this case was to get the focus on the fact that everything inside php and apache modules worked correctly and something in the outer environment of them must have been wrong, and thereafter to shift the view to anything in the code that could possibly influence that outer environment (e.g. the protocol version).

PHP cURL get requesting host

I have two PHP based sites http://domain1.tld and http://domain2.tld. From domain1.tld I start a cURL (get) request to domain2.tld.
How can I get the requesting host ("domain1.tld")?
I tried var_dump($_SERVER) and var_dump(apache_request_headers())but these didn't give me the requesting host.
One more important information: domain2.tld is running in CGI mode.
Many thanks in advance!
use the $_SERVER super global on http://domain2.tld
You can try either $_SERVER["REMOTE_HOST"] for the host name,
and if that doesn't work, the $_SERVER["REMOTE_ADDR"] will give you the corresponding IP-address

verify a website by uploading a file can be spoofed?

In my website i have a website verification process based on a file
The user has to upload in his root directory a empty file with a filename like this:
site-verification-$user_id.html
then my script use the php get_headers() function to check if this file exist, for example:
$headers = get_headers( "$user_website/site-verification-$user_id.html" );
if( preg_match( "|200|", $headers[0] ) { // ... website verified
everything works fine, but my question is, can this process be spoofed?
Yes, actually it's really easy to trick this mechanism. You just have to set up a webserver to catch all requests (e.g. via Apache's mod_rewrite configuration) and answer every single one of them with a valid response including HTTP-Status-Code 200 - pretty easy to set up.
If the User-Agent and/or IP of your webserver is known it would even be possible to lie specifically to your server while keeping up correct responses to all other visitors.
To be sure that this doesn't happen, you should give the user a randomly generated key that is then required as the content of the named file. You should then save the filename and the key in a DB and check both for compliance (analogous to how you would handle a combination of username and password).
This method is similiar to e.g. how you authenticate as the owner of a domain at Google Webmaster Tools. You can be pretty sure that only someone with access to the server can deposit this code at the specified address.
Keep in mind that "someone with access to the server" might still be someone without legitimate access. Also, an attacker executing a MITM attack between your own server and the server you are checking could send back whatever is needed to fool your server. Well, but then everything is lost either way.

When I run following url on my browser it runs fine but when i use php function its getting 505 Page . Can any one help me with that

$output = file_get_contents("http://www.canadapost.ca/cpc2/addrm/hh/current/indexa/caONu-e.asp");
var_dump($output);
HTTP 505 Status means the webserver does not support the HTTP version used by the client (in this case, your PHP program).
What version of PHP are you running, and what HTTP/Web package(s) are you using in your PHP program?
[edit...]
Some servers deliberately block some browsers -- your code may "look like" a browser that the server is configured to ignore. I would particularly check the user agent string that your code is passing along to the server.
Check in your PHP installation (php.ini file) if the allow_url_fopen is enabled.
If not, any calls to file_get_contents will fail.
It works fine for me.
That site could be blocking the server that you're using to access it.
When you run the URL from your browser, your own ISP is used to get the information and display in your browser. But when you run from PHP, the ISP of your web host is used to get the information, then it passes it back to you.
Maybe you can do this to check and see what kind of headers its returning for you?
$headers=get_headers("http://www.canadapost.ca/cpc2/addrm/hh/current/indexa/caONu-e.asp");
print_r($headers);

Categories