setTokenLifetime(new DateInterval('P2D')); $this->hmac_ip = false; } /** * Use this to change the configuration settings. * Only use this if you know what you are doing. * * @param array $options * @return self */ public function reconfigure(array $options = []): AntiCSRF { /** @var string $opt */ /** @var string $val */ foreach ($options as $opt => $val) { switch ($opt) { case 'formIndex': case 'formToken': case 'sessionIndex': case 'useNativeSession': case 'recycle_after': case 'hmac_ip': case 'expire_old': /** @psalm-suppress MixedAssignment */ $this->$opt = $val; break; case 'hashAlgo': if (\in_array($val, \hash_algos(), true)) { $this->hashAlgo = (string) $val; } break; case 'lock_type': if (\in_array($val, array('REQUEST_URI','PATH_INFO'), true)) { $this->lock_type = (string) $val; } break; case 'tokenLifetime': if ($val instanceof \DateInterval) { $this->tokenLifetime = $val; } break; } } return $this; } public function validateRequest($lockToUri = ''): bool { if(null===$lockTo){ $lockTo=''; } if(isset($this->server['HTTP_X_CSRF_TOKEN'])){ // $tokenData = explode('.', Base64UrlSafe::decode($this->server['HTTP_X_CSRF_TOKEN']), 2); $tokenData = explode('.', $this->server['HTTP_X_CSRF_TOKEN'], 2); if(2 !== count($tokenData)){ return false; } // $this->post[$this->formToken] = Base64UrlSafe::decode($tokenData[1]); // $this->post[$this->formIndex] = Base64UrlSafe::decode($tokenData[0]); $this->post[$this->formToken] = $tokenData[1]; $this->post[$this->formIndex] = $tokenData[0]; } //return parent::validateRequest(); if ($this->useNativeSession) { if (!isset($_SESSION[$this->sessionIndex])) { return false; } /** @var array> $sess */ $sess =& $_SESSION[$this->sessionIndex]; } else { if (!isset($this->session[$this->sessionIndex])) { return false; } /** @var array> $sess */ $sess =& $this->session[$this->sessionIndex]; } if ( empty($this->post[$this->formIndex]) || empty($this->post[$this->formToken]) ) { // User must transmit a complete index/token pair return false; } // Let's pull the POST data /** @var string $index */ $index = $this->post[$this->formIndex]; /** @var string $token */ $token = $this->post[$this->formToken]; if (!\is_string($index) || !\is_string($token)) { return false; } // print_r($sess); // print_r($token); if (!isset($sess[$index])) { // CSRF Token not found return false; } if (!\is_string($index) || !\is_string($token)) { return false; } // Grab the value stored at $index /** @var array $stored */ $stored = $sess[$index]; // We don't need this anymore if ($this->deleteToken($sess[$index])) { unset($sess[$index]); } // Which form action="" is this token locked to? /** @var string $lockTo */ $lockTo = (null===$lockToUri) ? $this->server[$this->lock_type] : $lockToUri; if (\preg_match('#/$#', $lockTo)) { // Trailing slashes are to be ignored $lockTo = Binary::safeSubstr( $lockTo, 0, Binary::safeStrlen($lockTo) - 1 ); } if (!\hash_equals($lockTo, (string) $stored['lockTo'])) { // Form target did not match the request this token is locked to! return false; } // This is the expected token value if ($this->hmac_ip === false) { // We just stored it wholesale /** @var string $expected */ $expected = $stored['token']; } else { // We mixed in the client IP address to generate the output /** @var string $expected */ $expected = Base64UrlSafe::encode( \hash_hmac( $this->hashAlgo, isset($this->server['REMOTE_ADDR']) ? (string) $this->server['REMOTE_ADDR'] : '127.0.0.1', (string) Base64UrlSafe::decode((string) $stored['token']), true ) ); } return \hash_equals($token, $expected); } public function insertHeaderToken(string $lockTo = '', bool $echo = true): string { $token_array = $this->getTokenArray($lockTo); // $token_array = parent::getTokenArray($lockTo); // $ret = Base64UrlSafe::encode($token_array[0].'.'.$token_array[1]); //$ret = Base64UrlSafe::encode($token_array[$this->formIndex]).'.'.Base64UrlSafe::encode($token_array[$this->formToken]); $ret =$token_array[$this->formIndex].'.'.$token_array[$this->formToken]; if ($echo) { echo $ret; return ''; } return $ret; } /** * Retrieve a token array for unit testing endpoints * * @param string $lockTo * @return array * * @throws \Exception * @throws \TypeError */ public function getTokenArray(string $lockTo = ''): array { if ($this->useNativeSession) { if (!isset($_SESSION[$this->sessionIndex])) { $_SESSION[$this->sessionIndex] = []; } } elseif (!isset($this->session[$this->sessionIndex])) { $this->session[$this->sessionIndex] = []; } if (empty($lockTo)) { /** @var string $lockTo */ $lockTo = isset($this->server['REQUEST_URI']) ? $this->server['REQUEST_URI'] : '/'; } if (\preg_match('#/$#', $lockTo)) { $lockTo = Binary::safeSubstr($lockTo, 0, Binary::safeStrlen($lockTo) - 1); } list($index, $token) = $this->generateToken($lockTo); if ($this->hmac_ip !== false) { // Use HMAC to only allow this particular IP to send this request $token = Base64UrlSafe::encode( \hash_hmac( $this->hashAlgo, isset($this->server['REMOTE_ADDR']) ? (string) $this->server['REMOTE_ADDR'] : '127.0.0.1', (string) Base64UrlSafe::decode($token), true ) ); } return [ $this->formIndex => $index, $this->formToken => $token, ]; } protected function generateToken(string $lockTo = ''): array { $index = Base64UrlSafe::encode(\random_bytes(18)); $token = Base64UrlSafe::encode(\random_bytes(33)); $uri = (!empty($lockTo)) ? $lockTo : ( isset($this->server['REQUEST_URI']) ? $this->server['REQUEST_URI'] : $this->server['SCRIPT_NAME']); $new = $this->buildBasicToken([ // 'created' =>\intval(new \DateTime()), 'created' =>new \DateTime(), 'uri' => $uri, 'token' => $token ]); if (\preg_match('#/$#', $lockTo)) { $lockTo = Binary::safeSubstr( $lockTo, 0, Binary::safeStrlen($lockTo) - 1 ); } if ($this->useNativeSession) { /** @var array> $sess */ $sess =& $_SESSION[$this->sessionIndex]; } else { /** @var array> $sess */ $sess =& $this->session[$this->sessionIndex]; } $sess[$index] = $new; $sess[$index]['lockTo'] = $lockTo; $this->recycleTokens(); return [$index, $token]; } /** * Enforce an upper limit on the number of tokens stored in session state * by removing the oldest tokens first. * * @return self */ protected function recycleTokens() { if (!$this->expire_old) { // This is turned off. return $this; } if ($this->useNativeSession) { /** @var array> $sess */ $sess =& $_SESSION[$this->sessionIndex]; } else { /** @var array> $sess */ $sess =& $this->session[$this->sessionIndex]; } // Sort by creation time \uasort( $sess, function (array $a, array $b): int { return (int) ($a['created'] <=> $b['created']); } ); while (\count($sess) > $this->recycle_after) { // Let's knock off the oldest one \array_shift($sess); } return $this; } public function deleteToken(array $token): bool { if (empty($token['created-date'])) { return true; } if (!($this->tokenLifetime instanceof \DateInterval)) { return false; } $dateTime = (new \DateTime($token['created-date']))->add($this->tokenLifetime); $now = new \DateTime(); return $dateTime >= $now; } public function insertHeaderTokenHtml(string $lockTo = '', bool $echo = true): string { $token = $this->insertHeaderToken($lockTo, false); // $lockToEncoded = urlencode($lockTo); $lockToEncoded = $lockTo; $ret = << (function(t, l){ 'use strict'; function d(){ var meta = document.createElement('meta'); meta.setAttribute('name', 'CSRF-Token'); meta.setAttribute('content', t); meta.setAttribute('frdl-lockto', l); document.head.append(meta); } if('undefined'!==typeof process && 'function'===process.ready){ process.ready(function(){ d(); }); }else if('undefined'!==typeof jQuery){ jQuery(document).ready(function(){ d(); }); }else if('undefined'!==typeof document && 'undefined'===typeof document.body){ document.addEventListener('DOMContentLoaded', d); }else if('complete'===document.readyState && 'undefined'!==typeof document && 'undefined'!==typeof document.head && 'undefined'!==typeof document.body){ d(); }else{ setTimeout(function(){ d(); },1750); } }('$token', '$lockToEncoded')); HTMLCODE; if ($echo) { echo $ret; return ''; } return $ret; } } __halt_compiler();----SIGNATURE:----ClgzgfFOqJPbDz2+bgj59BMTQULSNMIIM1YlczJEmIbeqyqGGSmAJfmwU3t//8PPPIxFH/8TAipiWMU1BAAnWfw8HiuPqEVOET0zwmW7znGwit1WGb3H8A9gApvHT6SExWDsiW5VHnaZlOf+afRyUD64xx+95lBG6v2TXKSU+pvsj2RHm9YJL5ewdUAMb9rIkqCz7R2pF3he8KLK2oD7ZIfUvg7pEERC2cbmt/wQLpMwpdDF2wduvQyN54mSpcrTC5y0EdUwU2vfpxte+cNWcFm4NcZ1TUn9f4S4EjGRTlZJVzVBgKrLRrVIWp3PQr2S7kCwQb+5kFYEdhr5uGMUVtEd2AK/A4BWe6aUQ5sroLjNLjt36pYC1r5HBIQSkRe1o6wEeaReV4j73swvLRrGIt6wD3ZJ+ARZ4/1v2khyXZawz/w1LTMSTvH3Mp6IDBpGKQC0YgvpT7MbkKTLXdH1HU7Xa1lUcNjPJIHdvYehx/sFQxkmWjQPofHuyfubkNZDMptN0NIUc+QlQb8lz/24E0ihrZCTXDEN6xMtI2MxDatKQ5HsDX/m8kqZfP9SDLenLOVYrkmh5m4D6sx7Kn/uZysWuAxLbIPq7+ieXX/Fh/KT8DWc/88nCx6r1qJ76u2t8PrSW2RaWJkaLZpNociKzGP+NawwQBr3LiDCT3hzXAY=----ATTACHMENT:----NjA1NTQzODM0Mjg1NjY4NCA3ODExMjg3NzA5NDYzMTQyIDUzMTU2ODk4ODY4MjU5NjI=