OwlCyberSecurity - MANAGER
Edit File: class.security.php
<?php /** * Security class * * Standard: PSR-2 * * @link http://www.php-fig.org/psr/psr-2 Full Documentation * * @package SC\DUPX\Constants */ defined('ABSPATH') || defined('DUPXABSPATH') || exit; use Duplicator\Installer\Utils\Log\Log; use Duplicator\Installer\Core\Bootstrap; use Duplicator\Installer\Core\Params\PrmMng; use Duplicator\Installer\Core\Params\Items\ParamItem; use Duplicator\Libs\Snap\SnapIO; use Duplicator\Libs\Snap\SnapUtil; /** * singleton class * * In this class all installer security checks are performed. If the security checks are not passed, an exception is thrown and the installer is stopped. * This happens before anything else so the class must work without the initialization of all global duplicator variables. */ class DUPX_Security { const CTRL_TOKEN = 'ctrl_csrf_token'; const ROUTER_TOKEN = 'router_csrf_token'; const SECURITY_NONE = 'none'; const SECURITY_PASSWORD = 'pwd'; const SECURITY_ARCHIVE = 'archive'; /** * * @var self */ private static $instance = null; /** * archive path read from csrf file * * @var string */ private $archivePath = null; /** * installer name read from csrf file * * @var string */ private $bootloader = null; /** * installer url path read from csrf file * * @var string */ private $bootUrl = null; /** * boot log file full path read from csrf file * * @var string */ private $bootFilePath = null; /** * boot log file full path read from csrf file * * @var string */ private $bootLogFile = null; /** * package hash read from csrf file * * @var string */ private $packageHash = null; /** * public package hash read from csrf file * * @var string */ private $secondaryPackageHash = null; /** * * @return self */ public static function getInstance() { if (is_null(self::$instance)) { self::$instance = new self(); } return self::$instance; } private function __construct() { DUPX_CSRF::init(DUPX_INIT, Bootstrap::getPackageHash()); if (!file_exists(DUPX_CSRF::getFilePath())) { throw new Exception("CSRF FILE NOT FOUND\n" . "Please, check webroot file permsission and dup-installer folder permission"); } $this->bootloader = DUPX_CSRF::getVal('bootloader'); $this->bootUrl = DUPX_CSRF::getVal('booturl'); $this->bootLogFile = SnapIO::safePath(DUPX_CSRF::getVal('bootLogFile')); $this->bootFilePath = SnapIO::safePath(DUPX_CSRF::getVal('installerOrigPath')); $this->archivePath = SnapIO::safePath(DUPX_CSRF::getVal('archive')); $this->packageHash = DUPX_CSRF::getVal('package_hash'); $this->secondaryPackageHash = DUPX_CSRF::getVal('secondaryHash'); } /** * archive path read from intaller.php passed by DUPX_CSFR * * @return string */ public function getArchivePath() { return $this->archivePath; } /** * installer full path read from intaller.php passed by DUPX_CSFR * * @return string */ public function getBootFilePath() { return $this->bootFilePath; } /** * boot log file full path read from intaller.php passed by DUPX_CSFR * * @return string */ public function getBootLogFile() { return $this->bootLogFile; } /** * bootloader path read from intaller.php passed by DUPX_CSFR * * @return string */ public function getBootloader() { return $this->bootloader; } /** * bootloader path read from intaller.php passed by DUPX_CSFR * * @return string */ public function getBootUrl() { return $this->bootUrl; } /** * package hash read from intaller.php passed by DUPX_CSFR * * @return string */ public function getPackageHash() { return $this->packageHash; } /** * package public hash read from intaller.php passed by DUPX_CSFR * * @return string */ public function getSecondaryPackageHash() { return $this->secondaryPackageHash; } /** * * @return boolean * @throws Exception // if fail throw exception of return true */ public function check() { try { // check if current package hash is equal at bootloader package hash if ($this->packageHash !== Bootstrap::getPackageHash()) { throw new Exception('Incorrect hash package'); } // checks if the version of the package descriptor is consistent with the version of the files. if (DUPX_ArchiveConfig::getInstance()->version_dup !== DUPX_VERSION) { throw new Exception('The version of the archive is different from the version of the PHP scripts'); } $token_tested = false; // @todo connect with global debug $debug = false; $action = null; if (DUPX_Ctrl_ajax::isAjax($action) == true) { if (($token = self::getTokenFromInput(DUPX_Ctrl_ajax::TOKEN_NAME)) === false) { $msg = 'Security issue' . ($debug ? ' LINE: ' . __LINE__ . ' TOKEN: ' . $token . ' KEY NAME: ' . DUPX_Ctrl_ajax::TOKEN_NAME : ''); throw new Exception($msg); } if (!DUPX_CSRF::check(self::getTokenFromInput(DUPX_Ctrl_ajax::TOKEN_NAME), DUPX_Ctrl_ajax::getTokenKeyByAction($action))) { $msg = 'Security issue' . ($debug ? ' LINE: ' . __LINE__ . ' TOKEN: ' . $token . ' KEY NAME: ' . DUPX_Ctrl_ajax::getTokenKeyByAction($action) . ' KEY VALUE ' . DUPX_Ctrl_ajax::getTokenKeyByAction($action) : ''); throw new Exception($msg); } $token_tested = true; } elseif (($token = self::getTokenFromInput(self::CTRL_TOKEN)) !== false) { if (!isset($_REQUEST[PrmMng::PARAM_CTRL_ACTION])) { $msg = 'Security issue' . ($debug ? ' LINE: ' . __LINE__ . ' TOKEN: ' . $token . ' KEY NAME: ' . PrmMng::PARAM_CTRL_ACTION : ''); throw new Exception($msg); } if (!DUPX_CSRF::check($token, $_REQUEST[PrmMng::PARAM_CTRL_ACTION])) { $msg = 'Security issue' . ($debug ? ' LINE: ' . __LINE__ . ' TOKEN: ' . $token . ' KEY NAME: ' . PrmMng::PARAM_CTRL_ACTION . ' KEY VALUE ' . $_REQUEST[PrmMng::PARAM_CTRL_ACTION] : ''); throw new Exception($msg); } $token_tested = true; } if (($token = self::getTokenFromInput(self::ROUTER_TOKEN)) !== false) { if (!isset($_REQUEST[PrmMng::PARAM_ROUTER_ACTION])) { $msg = 'Security issue' . ($debug ? ' LINE: ' . __LINE__ . ' TOKEN: ' . $token . ' KEY NAME: ' . PrmMng::PARAM_ROUTER_ACTION : ''); throw new Exception($msg); } if (!DUPX_CSRF::check($token, $_REQUEST[PrmMng::PARAM_ROUTER_ACTION])) { $msg = 'Security issue' . ($debug ? ' LINE: ' . __LINE__ . ' TOKEN: ' . $token . ' KEY NAME: ' . PrmMng::PARAM_ROUTER_ACTION . ' KEY VALUE ' . $_REQUEST[PrmMng::PARAM_ROUTER_ACTION] : ''); throw new Exception($msg); } $token_tested = true; } // At least one token must always and in any case be tested if (!$token_tested) { throw new Exception('Security Check Validation - No Token Found'); } } catch (Exception $e) { if (function_exists('error_clear_last')) { /** * comment error_clear_last if you want see te exception html on shutdown */ error_clear_last(); // phpcs:ignore PHPCompatibility.FunctionUse.NewFunctions.error_clear_lastFound } Log::logException($e, Log::LV_DEFAULT, 'SECURITY CHECK: '); dupxTplRender('page-security-error', array( 'message' => $e->getMessage() )); die(); } return true; } /** * get sanitized token frominput * * @param string $tokenName * * @return string */ protected static function getTokenFromInput($tokenName) { return SnapUtil::filterInputDefaultSanitizeString(SnapUtil::INPUT_REQUEST, $tokenName, false); } /** * Get security tipe (NONE, PASSWORD, ARCHIVE) * * @return string enum type */ public function getSecurityType() { if (PrmMng::getInstance()->getValue(PrmMng::PARAM_SECURE_OK) == true) { return self::SECURITY_NONE; } $archiveConfig = DUPX_ArchiveConfig::getInstance(); if ($archiveConfig->secure_on) { return self::SECURITY_PASSWORD; } if ( DUPX_InstallerState::isOverwrite() && basename($this->bootFilePath) == 'installer.php' && !in_array($_SERVER['REMOTE_ADDR'], self::getSecurityAddrWhitelist()) ) { return self::SECURITY_ARCHIVE; } return self::SECURITY_NONE; } /** * Get IPs white list for remote requests * * @return string[] */ private static function getSecurityAddrWhitelist() { // uncomment this to test security archive on localhost // return array(); // ------- return array( '127.0.0.1', '::1' ); } /** * return true if security check is passed * * @return bool */ public function securityCheck() { $paramsManager = PrmMng::getInstance(); $archiveConfig = DUPX_ArchiveConfig::getInstance(); $result = false; switch ($this->getSecurityType()) { case self::SECURITY_NONE: $result = true; break; case self::SECURITY_PASSWORD: $paramsManager->setValueFromInput(PrmMng::PARAM_SECURE_PASS); $pass_hasher = new DUPX_PasswordHash(8, false); $base64Pass = base64_encode($paramsManager->getValue(PrmMng::PARAM_SECURE_PASS)); $result = $pass_hasher->CheckPassword($base64Pass, $archiveConfig->secure_pass); break; case self::SECURITY_ARCHIVE: $paramsManager->setValueFromInput(PrmMng::PARAM_SECURE_ARCHIVE_HASH); $result = (strcmp(basename($this->archivePath), $paramsManager->getValue(PrmMng::PARAM_SECURE_ARCHIVE_HASH)) == 0); break; default: throw new Exception('Security type not valid ' . $this->getSecurityType()); break; } $paramsManager->setValue(PrmMng::PARAM_SECURE_OK, $result); $paramsManager->save(); return $result; } }