Current Path : /home/bitrix/ext_www/klimatlend.ua/bitrix/modules/security/lib/ |
Current File : /home/bitrix/ext_www/klimatlend.ua/bitrix/modules/security/lib/hostrestriction.php |
<?php /** * Bitrix Framework * @package bitrix * @subpackage security * @copyright 2001-2013 Bitrix */ namespace Bitrix\Security; use Bitrix\Main\Config; use Bitrix\Main\Context; use Bitrix\Main\Data; use Bitrix\Main\EventManager; use Bitrix\Main\Loader; use Bitrix\Main\ArgumentNullException; use Bitrix\Main\ArgumentOutOfRangeException; use Bitrix\Main\ArgumentTypeException; /** * Class HostRestriction * @since 14.0.6 * @example tests/security/hosts/basic.php * @package Bitrix\Security */ class HostRestriction { const ACTION_REDIRECT = 'redirect'; const ACTION_STOP = 'stop'; private $optionPrefix = 'restriction_hosts_'; private $cacheInitPath = 'security'; private $cacheId = 'restriction_hosts'; private $cacheTtl = 31536000; //one year private $action = 'stop'; private $actionOptions = array(); private $isLogNeeded = true; private $hosts = null; private $validActions = array( self::ACTION_REDIRECT, self::ACTION_STOP ); private $validationRegExp = null; private $isActive = null; /** * Handler for system event "OnPageStart", does nothing in CLI mode because it does not make sense * * @return void */ public static function onPageStart() { if (\CSecuritySystemInformation::isCliMode()) return; /** @var HostRestriction $instance */ $instance = new static; $instance->process(); } public function __construct() { $this->hosts = Config\Option::get('security', $this->optionPrefix.'hosts', ''); $this->action = Config\Option::get('security', $this->optionPrefix.'action', ''); $this->actionOptions = unserialize(Config\Option::get('security', $this->optionPrefix.'action_options', '{}')); $this->isLogNeeded = Config\Option::get('security', $this->optionPrefix.'logging', false); } /** * The main method that checks the current host, logging and starting action * * @param string $host Requested host for checking. * @return $this */ public function process($host = null) { if (is_null($host)) $host = $this->getTargetHost(); if ($this->isValidHost($host)) return $this; if ($this->isLogNeeded) $this->log($host); $this->doActions(); return $this; } /** * Checking host by host restriction policy * * @param string $host Host for checking. * @return bool Return true for valid (allowed) host. * @throws \Bitrix\Main\ArgumentTypeException */ public function isValidHost($host) { return (bool) ( is_string($host) && $host !== '' && preg_match($this->getValidationRegExp(), $host) > 0 ); } /** * @return array */ public function getProperties() { return array( 'hosts' => $this->hosts, 'current_host' => $this->getTargetHost(), 'action' => $this->action, 'action_options' => $this->actionOptions, 'logging' => $this->isLogNeeded, 'active' => is_null($this->isActive)? $this->getActive(): $this->isActive ); } /** * Set various properties for host checking, now support: * - hosts: a string with allowed hosts (wild card supported, e.g.: *.example.com) {@see setHosts} * - action: a string with action for unallowed host {@see validActions} * - action_options: array with some options for action {@see setAction} * - logging: bool, set true if need logging unallowed host {@see setLogging} * - active: bool, set true if automatic checking on every request needed * * @param array $properties See above. * @throws \Bitrix\Main\ArgumentOutOfRangeException * @throws \Bitrix\Main\ArgumentTypeException * @throws \Bitrix\Main\ArgumentNullException * @throws LogicException * @return $this */ public function setProperties(array $properties) { if (isset($properties['hosts'])) { $this->setHosts($properties['hosts']); } if (isset($properties['action'])) { if (isset($properties['action_options'])) { $this->setAction($properties['action'], $properties['action_options']); } else { $this->setAction($properties['action']); } } if (isset($properties['logging'])) { $this->setLogging($properties['logging']); } if (isset($properties['active'])) { $this->setActive($properties['active']); } return $this; } /** * @return string */ public function getAction() { return $this->action; } /** * @return array */ public function getActionOptions() { return $this->actionOptions; } /** * Set action performed while checking * * @param string $action Some action, now supported: redirect and stop. * @param array $options Some options for action, so far supported only host for redirect in redirect action. * @return $this * @throws \Bitrix\Security\LogicException * @throws \Bitrix\Main\ArgumentTypeException * @throws \Bitrix\Main\ArgumentNullException * @throws \Bitrix\Main\ArgumentOutOfRangeException */ public function setAction($action, array $options = array()) { if (!$action) throw new ArgumentNullException('action'); if (!is_string($action)) throw new ArgumentTypeException('action', 'string'); if (!in_array($action, $this->validActions)) throw new ArgumentOutOfRangeException('action', $this->validActions); if ($action === self::ACTION_REDIRECT) { if (!isset($options['host']) || !$options['host']) throw new LogicException('options[host] not present', 'SECURITY_HOSTS_EMPTY_HOST_ACTION'); if (!preg_match('#^https?://#', $options['host'])) throw new LogicException('invalid redirecting host present in options[host]', 'SECURITY_HOSTS_INVALID_HOST_ACTION'); } $this->action = $action; $this->actionOptions = $options; return $this; } /** * @return bool */ public function getLogging() { return $this->isLogNeeded; } /** * Activate or deactivate logging on unallowed host requested * * @param bool $isLogNeeded Set true if need logging unallowed host. * @return $this * @throws \Bitrix\Main\ArgumentTypeException */ public function setLogging($isLogNeeded = true) { if (!is_bool($isLogNeeded)) throw new ArgumentTypeException('isLogNeeded', 'bool'); $this->isLogNeeded = $isLogNeeded; return $this; } /** * @return bool */ public function getActive() { if (is_null($this->isActive)) $this->isActive = $this->isBound(); return $this->isActive; } /** * Activate or deactivate automatic checking * * @param bool $isActive Set true for enable checking on every request. * @throws \Bitrix\Main\ArgumentTypeException * @return $this */ public function setActive($isActive = false) { if (!is_bool($isActive)) throw new ArgumentTypeException('isActive', 'bool'); $this->isActive = $isActive; return $this; } /** * @return string */ public function getHosts() { return $this->hosts; } /** * Set allowed hosts * * @param string $hosts Allowed hosts (wild card supported, e.g.: *.example.com). * @param bool $ignoreChecking Set false for disable host validating before set. * @throws \Bitrix\Main\ArgumentTypeException * @throws LogicException * @return $this */ public function setHosts($hosts, $ignoreChecking = false) { if (!is_string($hosts)) throw new ArgumentTypeException('host', 'string'); if (!$ignoreChecking) $this->checkNewHosts($hosts); $this->hosts = $hosts; return $this; } /** * Return regular expressions (based on hosts) for checking. * Note: regular expression is cached for performance improvement and auto cleared after saving {@see save} * * @return string */ public function getValidationRegExp() { if ($this->validationRegExp) return $this->validationRegExp; $cache = Data\Cache::createInstance(); if($cache->initCache($this->cacheTtl, $this->cacheId, $this->cacheInitPath) ) { $this->validationRegExp = $cache->getVars(); } else { $this->validationRegExp = $this->genValidationRegExp($this->hosts); $cache->startDataCache(); $cache->endDataCache($this->validationRegExp); } return $this->validationRegExp; } /** * Save all properties, enable automatic checking and clear cache if needed * * @return $this */ public function save() { Config\Option::set('security', $this->optionPrefix.'hosts', $this->hosts, ''); Config\Option::set('security', $this->optionPrefix.'action', $this->action, ''); Config\Option::set('security', $this->optionPrefix.'action_options', serialize($this->actionOptions), ''); Config\Option::set('security', $this->optionPrefix.'logging', $this->isLogNeeded, ''); if (!is_null($this->isActive)) { if ($this->isActive) { EventManager::getInstance() ->registerEventHandler('main', 'OnPageStart', 'security', get_class($this), 'onPageStart'); } else { EventManager::getInstance() ->unRegisterEventHandler('main', 'OnPageStart', 'security', get_class($this), 'onPageStart'); } } Data\Cache::createInstance()->clean($this->cacheId, $this->cacheInitPath); return $this; } /** * Return true if HostRestriction already handled on system event "OnPageStart" * * @return bool */ protected function isBound() { $handlers = EventManager::getInstance()->findEventHandlers('main', 'OnPageStart', array('security')); foreach($handlers as $handler) { if ($handler['TO_CLASS'] === get_class($this)) return true; } return false; } /** * Return requested host for checking * * @return string */ protected function getTargetHost() { static $host = null; if (is_null($host)) $host = Context::getCurrent()->getServer()->getHttpHost(); return $host; } /** * Logging current host by event manager * * @param string $host Requested host. * @return bool */ protected function log($host) { return \CSecurityEvent::getInstance()->doLog('SECURITY', 'SECURITY_HOST_RESTRICTION', 'HTTP_HOST', $host); } /** * Perform some actions when requested host is not allowed by host restriction policy * * @return $this */ protected function doActions() { switch($this->action) { case self::ACTION_STOP: /** @noinspection PhpIncludeInspection */ include Loader::getLocal('/admin/security_403.php'); die(); break; case self::ACTION_REDIRECT: localRedirect($this->actionOptions['host'], true); break; default: trigger_error('Unknown action', E_USER_WARNING); } return $this; } /** * Generates regular expression obtained from hosts * * @param string $hosts Allowed hosts (wild card supported, e.g.: *.example.com). * @return string */ protected function genValidationRegExp($hosts) { $hosts = trim($hosts); $hosts = preg_quote($hosts); $hosts = preg_replace( array('~\#.*~', '~\\\\\*~', '~\s+~s'), array('', '.*', '|'), $hosts ); return "#^\s*($hosts)(:\d+)?\s*$#iD"; } /** * Checks the host to detect logical errors (eg blocking the current host) * * @param string $hosts Allowed hosts (wild card supported, e.g.: *.example.com). * @return $this * @throws \Bitrix\Security\LogicException */ protected function checkNewHosts($hosts) { $this->validationRegExp = $this->genValidationRegExp($hosts); if (!preg_match($this->validationRegExp, $this->getTargetHost())) throw new LogicException('Current host blocked', 'SECURITY_HOSTS_SELF_BLOCK'); if (preg_match($this->validationRegExp, 'some-invalid-host.com')) throw new LogicException('Any host passed restrictions', 'SECURITY_HOSTS_ANY_HOST'); return $this; } }