/** * Validate a request based on $_SESSION and $_POST data * * @return bool */ public function check() : bool { if (!isset($_SESSION[$this->sessionIndex])) { // We don't even have a session array initialized $_SESSION[$this->sessionIndex] = []; return false; } if (!isset($_POST[self::FORM_TOKEN]) || !\is_string($_POST[self::FORM_TOKEN])) { return false; } if (\strpos($_POST[self::FORM_TOKEN], ':') === false) { return false; } // Let's pull the POST data list($index, $token) = \explode(':', $_POST[self::FORM_TOKEN]); if (empty($index) || empty($token)) { return false; } if (!isset($_SESSION[$this->sessionIndex][$index])) { // CSRF Token not found return false; } // Grab the value stored at $index $stored = $_SESSION[$this->sessionIndex][$index]; // We don't need this anymore unset($_SESSION[$this->sessionIndex][$index]); // Which form action="" is this token locked to? $lockTo = $_SERVER['REQUEST_URI']; if (\preg_match('#/$#', $lockTo)) { // Trailing slashes are to be ignored $lockTo = substr($lockTo, 0, strlen($lockTo) - 1); } if (!empty($stored['lockto'])) { if (!\hash_equals($lockTo, $stored['lockto'])) { // Form target did not match the request this token is locked to! return false; } } // This is the expected token value if ($this->hmacIP === false) { // We just stored it wholesale $expected = $stored['token']; } else { // We mixed in the client IP address to generate the output $expected = Base64UrlSafe::encode(CryptoUtil::raw_keyed_hash($_SERVER['REMOTE_ADDR'] ?? '127.0.0.1', Base64UrlSafe::decode($stored['token']))); } return \hash_equals($token, $expected); }