I'm using Nginx as a proxy for a Java web service.
My config looks like this:
location /webservice {
proxy_read_timeout 240;
proxy_connect_timeout 240;
proxy_pass http://127.0.0.1:8080/;
}
In my logs I'm seeing a lot of entries like this:
xx.xx.xx.xx - - [18/Oct/2011:02:44:23 +0000] "GET http://l04.member.in2.yahoo.com/config/login?login=email@example.com&passwd=password HTTP/1.0" 200 9 "-" "Mozilla/4.0 (compatible; MSIE 5.0; Series60/2.8 Nokia6630/4.06.0 Profile/MIDP-2.0 Configuration/CLDC-1.1)"
I've done some testing, as far as I can see my proxy isn't forwarding requests to external sites, but I'd like to block these requests all together and/or return a status code other than 200.
I've done this:
if ($request_method !~ ^(GET|HEAD|POST)$ ) { return 444; }
which blocks CONNECT attempts. Any ideas (beyond IP blocking) would be appreciated.
Best Answer
Nginx will accept connections and process them based on matching the server_name (which checks against the Host header). Nginx comes with a default server block configured to match all Hosts. This allows for processing of any request that comes to the server.
I like to setup a server block checking for an empty Host header, and also configure the default server to return a 403 error (e.g. if you try to access my server via its IP address). Each virtual host then gets its own configuration (i.e. any valid host matches a configuration, all others either hit the default server block or the empty host block).
Server for checking empty host:
Server for throwing a 403 on all not configured hosts:
It should be noted that the listen directive isn't necessary above (nginx listens on port 80 by default) - but my nginx running behind varnish, so doesn't actually listen on port 80.
In your case, you will add a 3rd server that will handle your reverse proxy requests:
You can test your config in a variety of ways (I am sure there are more, but these come to mind at the moment):
(I am using google.com as my test domain below, change it to your site of choice):
Specify the entire request in one go:
Specify the request and host header separately:
Setup an entry in your hosts file (on your server):
Use curl to try and fetch a page:
(In this case, the hosts file is telling your server that google.com can be found on your machine - which gets the request to nginx - remove the entry when done testing.)
Edit: It appears that the unintended consequence of the above is that invalid requests result in a 400 error. You can determine the root cause of this, if interested, by adding the 'info' parameter to your error_log directive. In my case, the following causes were associated with the 400 errors that I saw:
Using telnet with the one-line GET request (and no host header):
Random requests (non-standard) made:
Using telnet, waited too long:
Other common causes were:
Using curl produced the expected 444 error. I imagine there is some additional syntax to a valid request. At any rate, the 400 errors are processed before the 444s from my understanding, so it is likely that these will not go away for truly invalid requests.
I was able to successfully get a 444 error using telnet though, it required modifying my config a bit:
Note that in the above, the 'unspecified server name' (underscore) and blank host (double quotes) do not explicitly define the default server, so you must add 'default' to the listen line.
Telnet output:
Access log output: