Load Balancers, IPs, & SSL

Interesting problem recently. The load balancer sends you, the client, to one of many web servers. It passes along the originating IP which is yours. Now you make a page request and get sent to another server in the cluster. What is your IP? According to Apache/PHP it’s whatever the load balancer says you just came from if you solely rely on the REMOTE_ADDR environment variable (commonly accessed through $_SERVER or getenv()).

I’ve seen a couple examples but really, what it comes down to, is checking to see what the load balancer thinks the client IP is through out the visit. As a developer you’d have to check something like the output of phpinfo() to see what the index for that server variable is. There is no one-fits-all solution to this. Different distros, Apache mods/versions, PHP versions may all change how this is sent to your environment. Here is my version:

	function getIPAddres()
	{
		$addr = $_SERVER['REMOTE_ADDR'];
		
		if(!empty($_SERVER['HTTP_CLIENT_IP'])) {
			$addr = $_SERVER['HTTP_CLIENT_IP'];
		}
		
		if(!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
			$addr = $_SERVER['HTTP_X_FORWARDED_FOR'];
		}
		
		if(!empty($_SERVER['HTTP_NS_FORWARD'])) {
			$addr = $_SERVER['HTTP_NS_FORWARD'];
		}

		return $addr;
	}	

I’ve included a couple other versions of this magic variable but this will give you the actual IP being reported by the user’s header. Remember that this isn’t reliable since clients can spoof header info, come through proxies, etc.

Another thing that I’ve encountered is finding out that the load balancers maintain a SSL connection but communicate via plain old port 80. This makes checking for SSL a little trickier. We have to trust the load balancer is enforcing SSL. Here is a snippet:

	function isSSL()
	{
		if(!empty($_SERVER['HTTPS'])) {
			return TRUE;
		}
		
		if($_SERVER['SERVER_PORT'] == 443) {
			return TRUE;
		} 
		
		if(stripos($_SERVER['HTTP_REFERER'], "https://") !== FALSE 
              && stripos($_SERVER['HTTP_REFERER'], "https://") == 0) {
			return TRUE;
		}
		
		error_log("Failure: Connection type not SSL (HTTPS).");	
		return FALSE;
	} 

The third block may or may not work in your case. My applications are behind a load balancer that behaves in a way that forces me to check for an SSL connection in this manner. There are probably other places I can look.

There’s quite a few examples out there of how to do each of these. I figured I’d share my experiences and insight since this was a really frustrating set of problems to track down.

This entry was posted in Uncategorized. Bookmark the permalink.

Comments are closed.