From dddfd411bcc7dedfd5e47d6184565f7e6b4a7c6e Mon Sep 17 00:00:00 2001
From: Cerdic <cedric@yterium.com>
Date: Sat, 2 Jul 2016 09:28:52 +0000
Subject: [PATCH] Prise en compte complete des entetes
 HTTP_X_FORWARDED_(FOR|HOST|PORT|PROTO) utilises conventionnellement lors de
 la prise en charge des hits par un proxy (notamment pour gerer le https). On
 prend en compte les cas (rares) de double proxy, qui inserent possiblement
 des valeurs multiples dans HOST et FOR, separees par une virgule Le risque
 d'empoisonnement du cache est garanti par le fait que HTTP_X_FORWARDED_HOST
 est injecte dans le contexte des caches, evitant de melanger les caches des
 hits servis avec et sans HTTP_X_FORWARDED_HOST
 https://core.spip.net/projects/spip/repository/entry/spip/ecrire/public/assembler.php#L226

---
 ecrire/inc/utils.php   | 54 ++++++++++++++++++++----------------------
 ecrire/inc_version.php | 30 +++++++++++++++++++++++
 2 files changed, 56 insertions(+), 28 deletions(-)

diff --git a/ecrire/inc/utils.php b/ecrire/inc/utils.php
index 5806d6b871..e2900154ae 100644
--- a/ecrire/inc/utils.php
+++ b/ecrire/inc/utils.php
@@ -1743,37 +1743,35 @@ function url_de_base($profondeur = null) {
 		or (isset($_SERVER['HTTPS']) and
 			test_valeur_serveur($_SERVER['HTTPS']))
 	) ? 'https' : 'http';
-	if (isset($_SERVER['HTTP_X_FORWARDED_HOST'])) {
-		$host = strtr($_SERVER['HTTP_X_FORWARDED_HOST'], "<>?\"' \r\n", '________');
-	} else {
-		// note : HTTP_HOST contient le :port si necessaire
-		$host = $_SERVER['HTTP_HOST'];
-		// si on n'a pas trouvé d'hôte du tout, en dernier recours on utilise adresse_site comme fallback
-		if (is_null($host) and isset($GLOBALS['meta']['adresse_site'])) {
-			$host = $GLOBALS['meta']['adresse_site'];
-			if ($scheme = parse_url($host, PHP_URL_SCHEME)) {
-				$http = $scheme;
-				$host = str_replace("{$scheme}://", '', $host);
-			}
+
+	// note : HTTP_HOST contient le :port si necessaire
+	$host = $_SERVER['HTTP_HOST'];
+	// si on n'a pas trouvé d'hôte du tout, en dernier recours on utilise adresse_site comme fallback
+	if (is_null($host) and isset($GLOBALS['meta']['adresse_site'])) {
+		$host = $GLOBALS['meta']['adresse_site'];
+		if ($scheme = parse_url($host, PHP_URL_SCHEME)) {
+			$http = $scheme;
+			$host = str_replace("{$scheme}://", '', $host);
 		}
-		if (isset($_SERVER['SERVER_PORT'])
-			and $port = $_SERVER['SERVER_PORT']
-			and strpos($host, ":") == false
-		) {
-			if (!defined('_PORT_HTTP_STANDARD')) {
-				define('_PORT_HTTP_STANDARD', '80');
-			}
-			if (!defined('_PORT_HTTPS_STANDARD')) {
-				define('_PORT_HTTPS_STANDARD', '443');
-			}
-			if ($http == "http" and !in_array($port, explode(',', _PORT_HTTP_STANDARD))) {
-				$host .= ":$port";
-			}
-			if ($http == "https" and !in_array($port, explode(',', _PORT_HTTPS_STANDARD))) {
-				$host .= ":$port";
-			}
+	}
+	if (isset($_SERVER['SERVER_PORT'])
+		and $port = $_SERVER['SERVER_PORT']
+		and strpos($host, ":") == false
+	) {
+		if (!defined('_PORT_HTTP_STANDARD')) {
+			define('_PORT_HTTP_STANDARD', '80');
+		}
+		if (!defined('_PORT_HTTPS_STANDARD')) {
+			define('_PORT_HTTPS_STANDARD', '443');
+		}
+		if ($http == "http" and !in_array($port, explode(',', _PORT_HTTP_STANDARD))) {
+			$host .= ":$port";
+		}
+		if ($http == "https" and !in_array($port, explode(',', _PORT_HTTPS_STANDARD))) {
+			$host .= ":$port";
 		}
 	}
+
 	if (!$GLOBALS['REQUEST_URI']) {
 		if (isset($_SERVER['REQUEST_URI'])) {
 			$GLOBALS['REQUEST_URI'] = $_SERVER['REQUEST_URI'];
diff --git a/ecrire/inc_version.php b/ecrire/inc_version.php
index 6e77256e8e..cfa62b9765 100644
--- a/ecrire/inc_version.php
+++ b/ecrire/inc_version.php
@@ -206,11 +206,41 @@ $filtrer_javascript = 0;
 $debut_date_publication = null;
 
 
+//
+// Prendre en compte les entetes HTTP_X_FORWARDED_XX
+//
+if (isset($_SERVER['HTTP_X_FORWARDED_HOST'])){
+	if (isset($_SERVER['HTTP_X_FORWARDED_PORT']) and is_numeric($_SERVER['HTTP_X_FORWARDED_PORT'])){
+		$_SERVER['SERVER_PORT'] = $_SERVER['HTTP_X_FORWARDED_PORT'];
+		if (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) and $_SERVER['HTTP_X_FORWARDED_PROTO']==='https'){
+			$_SERVER['HTTPS'] = 'on';
+			if (isset($_SERVER['REQUEST_SCHEME'])) {
+				$_SERVER['REQUEST_SCHEME'] = 'https';
+			}
+		}
+	}
+	$host = $_SERVER['HTTP_X_FORWARDED_HOST'];
+	if (strpos($host,',')!==false){
+		$h = explode(',',$host);
+		$host = trim(reset($h));
+	}
+	// securite sur le contenu de l'entete
+	$host = strtr($host, "<>?\"' \r\n", '________');
+	$_SERVER['HTTP_HOST'] = $host;
+}
 //
 // On note le numero IP du client dans la variable $ip
 //
 if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
 	$ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
+	if (strpos($ip,',')!==false){
+		$ip = explode(',',$ip);
+		$ip = reset($ip);
+	}
+	// ecraser $_SERVER['REMOTE_ADDR'] si elle est en localhost
+	if (isset($_SERVER['REMOTE_ADDR']) AND $_SERVER['REMOTE_ADDR']==='127.0.0.1'){
+		$_SERVER['REMOTE_ADDR'] = $ip;
+	}
 }
 if (isset($_SERVER['REMOTE_ADDR'])) {
 	$ip = $_SERVER['REMOTE_ADDR'];
-- 
GitLab