From a1ffa1de1c91cca118a7cba2e2550a383ea0537e Mon Sep 17 00:00:00 2001 From: Martin Date: Thu, 13 Mar 2025 09:11:42 +0100 Subject: [PATCH 1/4] Fix XSS --- tileserver.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tileserver.php b/tileserver.php index d4e12d4..a5c5618 100755 --- a/tileserver.php +++ b/tileserver.php @@ -406,7 +406,7 @@ public function renderTile($tileset, $z, $y, $x, $ext) { $this->getCleanTile($meta->scale, $ext); } else { header('HTTP/1.1 404 Not Found'); - echo 'Server: Unknown or not specified dataset "' . $tileset . '"'; + echo 'Server: Unknown or not specified dataset "' . htmlspecialchars($tileset) . '"'; die; } } From 885bb9c5039b711aae48797c3bae7f560e27a3f6 Mon Sep 17 00:00:00 2001 From: Martin Date: Thu, 13 Mar 2025 09:30:58 +0100 Subject: [PATCH 2/4] Check if requested tile resides inside the current directory --- tileserver.php | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tileserver.php b/tileserver.php index a5c5618..c2166b1 100755 --- a/tileserver.php +++ b/tileserver.php @@ -383,6 +383,14 @@ public function renderTile($tileset, $z, $y, $x, $ext) { if($ext != null){ $name .= '.' . $ext; } + //check if the requested file is inside the current working directory + $requestedPath = realpath($name); + $allowedBasePath = realpath(getcwd()); + if (strpos($requestedPath, $allowedBasePath . DIRECTORY_SEPARATOR) !== 0) { + header('HTTP/1.1 404 Not Found'); + echo 'Server: Unknown or not specified dataset "' . htmlspecialchars($tileset) . '"'; + die; + } if ($fp = @fopen($name, 'rb')) { if($ext != null){ $mime .= $ext; From e24f80bd59bb237ecf20df8ef20e45d49ddd2e35 Mon Sep 17 00:00:00 2001 From: Martin Date: Thu, 13 Mar 2025 10:38:16 +0100 Subject: [PATCH 3/4] Add input validation for "renderTile" --- tileserver.php | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tileserver.php b/tileserver.php index c2166b1..6cabeb3 100755 --- a/tileserver.php +++ b/tileserver.php @@ -338,6 +338,16 @@ public function isModified($filename) { * @param string $ext */ public function renderTile($tileset, $z, $y, $x, $ext) { + //simple input validation + $z = (int)$z; + $y = (int)$y; + $x = (int)$x; + $alpharegex = '/^([a-zA-Z0-9-_@\.]*)$/'; + if (!preg_match($alpharegex, $tileset) || !preg_match($alpharegex, $ext)) { + header('HTTP/1.1 400 Bad Request'); + echo 'Server: Parameter validation failed.'; + die; + } if ($this->isDBLayer($tileset)) { if ($this->isModified($tileset) == true) { header('Access-Control-Allow-Origin: *'); From 1f7d3b1de471f5999a52768fc94ddeb99bdb40bb Mon Sep 17 00:00:00 2001 From: Martin Date: Thu, 13 Mar 2025 10:42:51 +0100 Subject: [PATCH 4/4] Use floatval instead of "int" for casting --- tileserver.php | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/tileserver.php b/tileserver.php index 6cabeb3..6ebedae 100755 --- a/tileserver.php +++ b/tileserver.php @@ -339,9 +339,9 @@ public function isModified($filename) { */ public function renderTile($tileset, $z, $y, $x, $ext) { //simple input validation - $z = (int)$z; - $y = (int)$y; - $x = (int)$x; + $z = floatval($z); + $y = floatval($y); + $x = floatval($x); $alpharegex = '/^([a-zA-Z0-9-_@\.]*)$/'; if (!preg_match($alpharegex, $tileset) || !preg_match($alpharegex, $ext)) { header('HTTP/1.1 400 Bad Request'); @@ -355,9 +355,6 @@ public function renderTile($tileset, $z, $y, $x, $ext) { die; } $this->DBconnect($this->config['dataRoot'] . $tileset . '.mbtiles'); - $z = floatval($z); - $y = floatval($y); - $x = floatval($x); $flip = true; if ($flip) { $y = pow(2, $z) - 1 - $y;