From 38b6bb94bb1d714f82e4b5419db7544153dee100 Mon Sep 17 00:00:00 2001 From: Stefan Gabos Date: Sun, 8 Sep 2024 11:36:44 +0300 Subject: [PATCH] More updates following the conversation on #56 - this reverts the fix for #54 and #43 and provides a more secure - but different - way for handling your app being behind a load balancer or a reverse proxy --- Zebra_Session.php | 66 +++++++++++++++++++---------------------------- 1 file changed, 26 insertions(+), 40 deletions(-) diff --git a/Zebra_Session.php b/Zebra_Session.php index 215f468..8e3399c 100644 --- a/Zebra_Session.php +++ b/Zebra_Session.php @@ -202,16 +202,18 @@ class Zebra_Session { * session was first opened. * * For the actual IP address that is going to be used, the library will - * check these entries in the $_SERVER superglobal, in this particular - * order:

- **HTTP_CLIENT_IP**
- **HTTP_X_FORWARDED_FOR**
- - * **HTTP_X_FORWARDED**
- **HTTP_FORWARDED_FOR**
- **HTTP_FORWARDED** - *
- **REMOTE_ADDR**

...and use whichever returns a result first. + * use the value of `$_SERVER['REMOTE_ADDR']`. * - * If you have this turned on but the above logic doesn't get you the IP - * address that you need, you can pass a **callable function** and whatever - * result returned by said function will be used as IP address (it doesn't - * even need to be an actual IP address but rather anything unique identifying - * a specific user) + * If your application is behind a load balancer like an AWS Elastic Load Balancing + * or a reverse proxy like Varnish, certain request information will be sent using + * either the standard `Forwarded` header or the `X-Forwarded-*` headers. In this case, + * the `REMOTE_ADDR` header will likely be the IP address of your reverse proxy while + * the user's true IP will be stored in a standard `Forwarded` header or an `X-Forwarded-For` + * header. + * + * In this case you will need to tell the library which reverse proxy IP addresses to + * trust and what headers your reverse proxy uses to send information by using a `callable` + * value for this argument: * * * new Zebra_Session( @@ -219,17 +221,23 @@ class Zebra_Session { * 'someSecur1tyCode!', * 0, * false, + * * // one way of using a callable for this argument * function() { - * return $_SERVER['whateverYouWant']; + * $ipaddress = ''; + * // use the header(s) you choose to trust + * foreach (['HTTP_X_FORWARDED_FOR', 'HTTP_X_FORWARDED', 'HTTP_FORWARDED_FOR', 'HTTP_FORWARDED'] as $key) { + * // use the first one containing a value + * if (($tmp = getenv($key))) { + * $ipaddress = $tmp; + * break; + * } + * } + * return $ipaddress; * } * ); * * - * > Use this with caution as users may have a dynamic IP address which - * may change over time, or may come through proxies. This is mostly - * useful if you know that all your users come from static IPs. - * * Default is `false` * * @param int $lock_timeout (Optional) The maximum amount of time (in seconds) for which a lock on @@ -558,11 +566,11 @@ public function read($session_id) { // if session is locked to an IP address // if "lock_to_ip" is truthy but *not* callable - // (this is the quickest way in case lock_to_ip is truthy) + // (this is the quickest way in case "lock_to_ip" is truthy) if ($this->lock_to_ip && !is_callable($this->lock_to_ip)) { - // append whatever is returned by "get_ip_address" - $hash .= $this->get_ip_address(); + // append the value of "REMOTE_ADDR" header + $hash .= $_SERVER['REMOTE_ADDR']; // if "lock_to_ip" is callable } elseif (is_callable($this->lock_to_ip)) { @@ -741,7 +749,7 @@ public function write($session_id, $session_data) { $session_id, md5( ($this->lock_to_user_agent && isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : '') . - ($this->lock_to_ip && !is_callable($this->lock_to_ip) ? $this->get_ip_address() : (is_callable($this->lock_to_ip) ? call_user_func($this->lock_to_ip) : '')) . + ($this->lock_to_ip && !is_callable($this->lock_to_ip) ? $_SERVER['REMOTE_ADDR'] : (is_callable($this->lock_to_ip) ? call_user_func($this->lock_to_ip) : '')) . $this->security_code ), $session_data, @@ -885,26 +893,4 @@ private function query($query) { } - /** - * Tries to get client's *real* IP address. - * - * This should return the same IP address when using something like an AWS load balancer. - * - * @return string - * - * @access private - */ - private function get_ip_address() { - - $ipaddress = ''; - foreach (['HTTP_CLIENT_IP', 'HTTP_X_FORWARDED_FOR', 'HTTP_X_FORWARDED', 'HTTP_FORWARDED_FOR', 'HTTP_FORWARDED', 'REMOTE_ADDR'] as $key) { - if (($tmp = getenv($key))) { - $ipaddress = $tmp; - break; - } - } - return $ipaddress; - - } - }