From 83d1796309d4de5ac7a2716c21653fd8ce066b3d Mon Sep 17 00:00:00 2001 From: Web Addicto Date: Mon, 6 Feb 2017 22:11:10 +0100 Subject: [PATCH 1/6] SecurityPlugin Simple plugin that improves the security of php-proxy by blocking proxify of localhost, internal IPs, server IP, server host, etc. --- src/SecurityPlugin.php | 50 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 src/SecurityPlugin.php diff --git a/src/SecurityPlugin.php b/src/SecurityPlugin.php new file mode 100644 index 0000000..78f68d6 --- /dev/null +++ b/src/SecurityPlugin.php @@ -0,0 +1,50 @@ + $error + )); + + header("HTTP/1.1 302 Found"); + header("Location: {$url}"); + + } + else { + + //$url = render_string(app_url()."?error={error_msg}", array( + //'error_msg' => $error + //)); + + //header("HTTP/1.1 302 Found"); + //header("Location: {$url}"); + + echo render_template("./templates/main.php", array( + 'url' => $url, + 'error_msg' => $error, + 'version' => Proxy::VERSION + )); + + } + + exit(); + } + + public function onBeforeRequest(ProxyEvent $event){ + + // Get URL + $url = $event['request']->getUri(); + + // Do not proxify invalid URLs + if(!filter_var($url, FILTER_VALIDATE_URL)){ + $this->ErrorMsg("URL is not valid"); + } From 554c672c7b9cb45d411769d9b71180f8d3f4632f Mon Sep 17 00:00:00 2001 From: Web Addicto Date: Mon, 6 Feb 2017 22:12:29 +0100 Subject: [PATCH 2/6] Updated the code --- src/SecurityPlugin.php | 47 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/src/SecurityPlugin.php b/src/SecurityPlugin.php index 78f68d6..14af9de 100644 --- a/src/SecurityPlugin.php +++ b/src/SecurityPlugin.php @@ -48,3 +48,50 @@ public function onBeforeRequest(ProxyEvent $event){ if(!filter_var($url, FILTER_VALIDATE_URL)){ $this->ErrorMsg("URL is not valid"); } + + // Do not proxify invalid scheme + // *** May not be needed because the php-proxy already adds http:// by default *** + if(!in_array(strtolower(parse_url($url, PHP_URL_SCHEME)), array("http","https","ftp"))){ + $this->ErrorMsg("Scheme is not allowed"); + } + + // Remove "www." from host + $url_host = preg_replace('/^www\./is', '', trim(parse_url($url, PHP_URL_HOST))); + + // Do not proxify localhost + if(preg_match('/^localhost/is', $url_host)){ + $this->ErrorMsg("Host is not allowed"); + } + + // Do not proxify internal IP addresses + if(filter_var($url_host, FILTER_VALIDATE_IP)){ + if(filter_var($url_host, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE) === false){ + $this->ErrorMsg("Host is not allowed"); + } + } + + // Do not proxify our own proxy host ($_SERVER['HTTP_HOST']) + if(stripos($url_host, $_SERVER['HTTP_HOST']) === 0){ + $this->ErrorMsg("Host is not allowed"); + } + + // Remove "www." from app_url() + $app_host = preg_replace('/^www\./is', '', trim(parse_url(app_url(), PHP_URL_HOST))); + + // Do not proxify our own proxy host (app_url()) + if(stripos($url_host, $app_host) === 0){ + $this->ErrorMsg("Host is not allowed"); + } + + // Do not proxify the server's IP address + if(filter_var($_SERVER['SERVER_ADDR'], FILTER_VALIDATE_IP)){ + if($url_host == $_SERVER['SERVER_ADDR']){ + $this->ErrorMsg("Host is not allowed"); + } + } + + } + +} + +?> From 0bfc25be74a97c69909b337fc847b1111e1e128f Mon Sep 17 00:00:00 2001 From: Web Addicto Date: Sat, 11 Feb 2017 15:14:30 +0100 Subject: [PATCH 3/6] Some improvements --- src/SecurityPlugin.php | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/SecurityPlugin.php b/src/SecurityPlugin.php index 14af9de..6ba685e 100644 --- a/src/SecurityPlugin.php +++ b/src/SecurityPlugin.php @@ -49,8 +49,17 @@ public function onBeforeRequest(ProxyEvent $event){ $this->ErrorMsg("URL is not valid"); } + // Do not proxify invalid URLs like http://file://aaa + if(preg_match('/.*:.*:/is', $url)){ + $this->ErrorMsg("URL is not valid"); + } + + // Do not proxify URLs that contain pattern of hidden folders or files + if(preg_match('/(\/\.|\.\.)/is', $url)){ + $this->ErrorMsg("URL is not valid"); + } + // Do not proxify invalid scheme - // *** May not be needed because the php-proxy already adds http:// by default *** if(!in_array(strtolower(parse_url($url, PHP_URL_SCHEME)), array("http","https","ftp"))){ $this->ErrorMsg("Scheme is not allowed"); } From 921053624b9df7c12282ff034191e5081ee94850 Mon Sep 17 00:00:00 2001 From: Web Addicto Date: Sat, 11 Feb 2017 20:00:14 +0100 Subject: [PATCH 4/6] Remove one rule for incompatibility with a site --- src/SecurityPlugin.php | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/SecurityPlugin.php b/src/SecurityPlugin.php index 6ba685e..d16ddc0 100644 --- a/src/SecurityPlugin.php +++ b/src/SecurityPlugin.php @@ -49,11 +49,6 @@ public function onBeforeRequest(ProxyEvent $event){ $this->ErrorMsg("URL is not valid"); } - // Do not proxify invalid URLs like http://file://aaa - if(preg_match('/.*:.*:/is', $url)){ - $this->ErrorMsg("URL is not valid"); - } - // Do not proxify URLs that contain pattern of hidden folders or files if(preg_match('/(\/\.|\.\.)/is', $url)){ $this->ErrorMsg("URL is not valid"); From 5690202a9558d6a9e3768a970de549d914bfc714 Mon Sep 17 00:00:00 2001 From: Web Addicto Date: Mon, 13 Feb 2017 16:44:46 +0100 Subject: [PATCH 5/6] Trim $url Important to correctly validate valid URLs that have spaces at the end or at begin. --- src/SecurityPlugin.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/SecurityPlugin.php b/src/SecurityPlugin.php index d16ddc0..651e66c 100644 --- a/src/SecurityPlugin.php +++ b/src/SecurityPlugin.php @@ -43,13 +43,16 @@ public function onBeforeRequest(ProxyEvent $event){ // Get URL $url = $event['request']->getUri(); + + // Trim URL (important to validate URL) + $url = trim($url); // Do not proxify invalid URLs if(!filter_var($url, FILTER_VALIDATE_URL)){ $this->ErrorMsg("URL is not valid"); } - // Do not proxify URLs that contain pattern of hidden folders or files + // Do not proxify URLs that contain pattern of hidden folders or files (i.e /.htpasswd) if(preg_match('/(\/\.|\.\.)/is', $url)){ $this->ErrorMsg("URL is not valid"); } From 772c78e2e23fa1fbb67b9c8e12c1c241ad82d397 Mon Sep 17 00:00:00 2001 From: Web Addicto Date: Sun, 3 Dec 2017 19:50:28 +0100 Subject: [PATCH 6/6] Rewrote it, not it is smaller and cleaner. --- src/SecurityPlugin.php | 85 +++++++++++++----------------------------- 1 file changed, 25 insertions(+), 60 deletions(-) diff --git a/src/SecurityPlugin.php b/src/SecurityPlugin.php index 651e66c..31e6f32 100644 --- a/src/SecurityPlugin.php +++ b/src/SecurityPlugin.php @@ -6,97 +6,62 @@ use Proxy\Proxy; class SecurityPlugin extends AbstractPlugin { - - private function ErrorMsg($error){ - - if(Config::get("error_redirect")){ - - $url = render_string(Config::get("error_redirect"), array( - 'error_msg' => $error - )); - - header("HTTP/1.1 302 Found"); - header("Location: {$url}"); - - } - else { - - //$url = render_string(app_url()."?error={error_msg}", array( - //'error_msg' => $error - //)); - - //header("HTTP/1.1 302 Found"); - //header("Location: {$url}"); - - echo render_template("./templates/main.php", array( - 'url' => $url, - 'error_msg' => $error, - 'version' => Proxy::VERSION - )); - - } - - exit(); - } public function onBeforeRequest(ProxyEvent $event){ - // Get URL - $url = $event['request']->getUri(); + // Get URL and trim it (important for FILTER_VALIDATE_URL) + $url = trim($event['request']->getUri()); + + // Remove "www." from url's host, example: www.google.fr -> google.fr + $url_host = preg_replace('/^www\./is', '', trim(parse_url($url, PHP_URL_HOST))); + + // Remove "www." from app_url(), example: www.proxyurl.com -> proxyurl.com + $app_host = preg_replace('/^www\./is', '', trim(parse_url(app_url(), PHP_URL_HOST))); - // Trim URL (important to validate URL) - $url = trim($url); - // Do not proxify invalid URLs if(!filter_var($url, FILTER_VALIDATE_URL)){ - $this->ErrorMsg("URL is not valid"); + throw new \Exception("URL is not valid"); } - // Do not proxify URLs that contain pattern of hidden folders or files (i.e /.htpasswd) + // Do not proxify URLs with "/.htpasswd" or "/../" (hidden folders or files) if(preg_match('/(\/\.|\.\.)/is', $url)){ - $this->ErrorMsg("URL is not valid"); + throw new \Exception("URL is not valid"); } - // Do not proxify invalid scheme - if(!in_array(strtolower(parse_url($url, PHP_URL_SCHEME)), array("http","https","ftp"))){ - $this->ErrorMsg("Scheme is not allowed"); + // Do not proxify URLs with invalid or unsupported scheme + if(!in_array(strtolower(parse_url($url, PHP_URL_SCHEME)), array("http","https"))){ + throw new \Exception("Scheme is not allowed"); } - // Remove "www." from host - $url_host = preg_replace('/^www\./is', '', trim(parse_url($url, PHP_URL_HOST))); - // Do not proxify localhost if(preg_match('/^localhost/is', $url_host)){ - $this->ErrorMsg("Host is not allowed"); + throw new \Exception("Host is not allowed"); } // Do not proxify internal IP addresses if(filter_var($url_host, FILTER_VALIDATE_IP)){ if(filter_var($url_host, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE) === false){ - $this->ErrorMsg("Host is not allowed"); + throw new \Exception("Host is not allowed"); + } + } + + // Do not proxify the server's IP address + if(filter_var($_SERVER['SERVER_ADDR'], FILTER_VALIDATE_IP)){ + if($url_host == $_SERVER['SERVER_ADDR']){ + throw new \Exception("Host is not allowed"); } } // Do not proxify our own proxy host ($_SERVER['HTTP_HOST']) if(stripos($url_host, $_SERVER['HTTP_HOST']) === 0){ - $this->ErrorMsg("Host is not allowed"); + throw new \Exception("Host is not allowed"); } - // Remove "www." from app_url() - $app_host = preg_replace('/^www\./is', '', trim(parse_url(app_url(), PHP_URL_HOST))); - // Do not proxify our own proxy host (app_url()) if(stripos($url_host, $app_host) === 0){ - $this->ErrorMsg("Host is not allowed"); + throw new \Exception("Host is not allowed"); } - // Do not proxify the server's IP address - if(filter_var($_SERVER['SERVER_ADDR'], FILTER_VALIDATE_IP)){ - if($url_host == $_SERVER['SERVER_ADDR']){ - $this->ErrorMsg("Host is not allowed"); - } - } - } }