logger = $logger; $this->matomoURL = SettingsPiwik::getPiwikUrl(); $this->criticalIssue = false; } public function execute() { //TODO: don't check if running in development mode $result = new DiagnosticResult("Files that should not be public"); $result->addItem($this->checkConfigIni()); $result->addItem($this->checkRequestNotAllowed( ".git/info/exclude", "Lines that start" )); $result->addItem($this->checkRequestNotAllowed( "tmp/cache/token.php", "?php exit" )); $result->addItem($this->checkRequestNotAllowed( "cache/tracker/matomocache_general.php", "unserialize" )); if ($this->criticalIssue) { $result->setLongErrorMessage( "Please check if your webserver processes the .htaccess files generated by Matomo properly. If you are using Nginx, please take a look at the official matomo-nginx config for reference.
Otherwise attackers might be able to read sensitive data." ); } return array($result); } /** * @return DiagnosticResultItem */ protected function checkConfigIni() { $relativeUrl = "config/config.ini.php"; list($status, $headers, $data) = $this->makeHTTPReququest($relativeUrl); if ($this->contains($data, "salt")) { return $this->isPublicError($relativeUrl, true); } if ($this->contains($data, ";")) { return new DiagnosticResultItem( DiagnosticResult::STATUS_WARNING, "$relativeUrl seems to be semi-public. " . "While attackers can't read the config now, the file is publicly accessible and if for whatever reason your webserver " . "stops executing PHP files, everyone can read your MySQL credentials and more" . "Please check your webserver config." ); } } protected function checkRequestNotAllowed($relativeUrl, $content, $critical = true): DiagnosticResultItem { list($status, $headers, $data) = $this->makeHTTPReququest($relativeUrl); // var_dump($data); if (strpos($data, $content) !== false) { return $this->isPublicError($relativeUrl, $critical); } return new DiagnosticResultItem(DiagnosticResult::STATUS_OK, "$relativeUrl doesn't seem to be publically reachable"); } protected function isPublicError($relativeUrl, $critical): DiagnosticResultItem { if ($critical) { $this->criticalIssue = true; } return new DiagnosticResultItem( $critical ? DiagnosticResult::STATUS_ERROR : DiagnosticResult::STATUS_WARNING, "$relativeUrl should never be public. Please check your webserver config." ); } protected function makeHTTPReququest($relativeUrl) { $response = Http::sendHttpRequest($this->matomoURL . $relativeUrl, self::SOCKET_TIMEOUT, $userAgent = null, $destinationPath = null, $followDepth = 0, $acceptLanguage = false, $byteRange = false, $getExtendedInfo = true); $status = $response["status"]; $headers = $response["headers"]; $data = $response["data"]; return [$status, $headers, $data]; } protected function contains(string $haystack, string $needle): bool { return strpos($haystack, $needle) !== false; } }