|
|
<?php |
|
|
|
|
|
namespace Kanboard\Core\Security; |
|
|
|
|
|
use Kanboard\Core\Base; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class Token extends Base |
|
|
{ |
|
|
protected static $KEY_LENGTH = 32; |
|
|
protected static $NONCE_LENGTH = 16; |
|
|
protected static $HMAC_ALGO = 'sha256'; |
|
|
protected static $HMAC_LENGTH = 16; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public static function getToken($length = 30) |
|
|
{ |
|
|
return bin2hex(random_bytes($length)); |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public function getCSRFToken() |
|
|
{ |
|
|
return $this->createSessionToken('csrf'); |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public function getReusableCSRFToken() |
|
|
{ |
|
|
return $this->createSessionToken('pcsrf'); |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public function validateCSRFToken($token) |
|
|
{ |
|
|
return $this->validateSessionToken('csrf', $token); |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public function validateReusableCSRFToken($token) |
|
|
{ |
|
|
return $this->validateSessionToken('pcsrf', $token); |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
protected function createSessionToken($type) |
|
|
{ |
|
|
$nonce = self::getToken(self::$NONCE_LENGTH); |
|
|
return $nonce . $this->signSessionToken($type, $nonce); |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
protected function validateSessionToken($type, $token) |
|
|
{ |
|
|
if (!is_string($token)) { |
|
|
return false; |
|
|
} |
|
|
|
|
|
if (strlen($token) != (self::$NONCE_LENGTH + self::$HMAC_LENGTH) * 2) { |
|
|
return false; |
|
|
} |
|
|
|
|
|
$nonce = substr($token, 0, self::$NONCE_LENGTH * 2); |
|
|
$hmac = substr($token, self::$NONCE_LENGTH * 2, self::$HMAC_LENGTH * 2); |
|
|
|
|
|
return hash_equals($this->signSessionToken($type, $nonce), $hmac); |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
protected function signSessionToken($type, $nonce) |
|
|
{ |
|
|
if (!session_exists($type . '_key')) { |
|
|
session_set($type . '_key', self::getToken(self::$KEY_LENGTH)); |
|
|
} |
|
|
|
|
|
$data = $nonce . '-' . session_id(); |
|
|
$key = session_get($type . '_key'); |
|
|
$hmac = hash_hmac(self::$HMAC_ALGO, $data, $key, true); |
|
|
|
|
|
return bin2hex(substr($hmac, 0, self::$HMAC_LENGTH)); |
|
|
} |
|
|
} |
|
|
|