Однократное использование маркера CSRF и проверка для межсерверной связи в PHP

Я много искал, пытаясь найти что-то для своей цели, однако большинство решений вращаются вокруг токенов CSRF, которые работают вместе с данными сеанса. Для моей цели требуется токен, основанный на времени, для межсерверной связи.

У меня есть Server A который должен получать и проверять токен, который отправляется ему через POST с Server B Маркер должен быть сгенерирован на Server B путем хэширования секретным ключом. Server A должен проверить его. Теперь проблема заключается в том, что токен должен быть ограничен одноразовым (возможно?) И должен истекать в зависимости от времени (например, 10 минут жизни). Поскольку это межсерверная связь, я не могу использовать сеанс.

Я боюсь, что не могу использовать базу данных или сеанс для хранения / проверки токена. Любые примеры кода были бы полезными.

Это требуется в среде PHP.

Solutions Collecting From Web of "Однократное использование маркера CSRF и проверка для межсерверной связи в PHP"

То, что вы можете сделать, это добавить метку времени к ключу токена, как когда она была создана, плюс IP-адрес запрашивающих, а затем, когда вы расшифруете проверку ключа, если время падает между допустимым временем или разрешает IP-адрес.

пример с фиксированным IP:

 <?php class csrf_check { const SALT = '_SECRET_'; public function create_api_key() { return base64_encode($this->encrypt(time().'|'.$_SERVER['REMOTE_ADDR'])); // !change if you dont want IP check } public function check_api_key($key, $timeout = 5) { if (empty($key)) exit('Invalid Key'); $keys = explode('|', $this->decrypt(base64_decode($key))); return ( isset($key, $keys[0], $keys[1]) && $keys[0] >= (time() - $timeout) && $keys[1] == $_SERVER['REMOTE_ADDR'] // !change if you dont want IP check ); } public function encrypt($string, $key = 'PrivateKey', $secret = 'SecretKey', $method = 'AES-256-CBC') { // hash $key = hash('sha256', $key); // create iv - encrypt method AES-256-CBC expects 16 bytes $iv = substr(hash('sha256', $secret), 0, 16); // encrypt $output = openssl_encrypt($string, $method, $key, 0, $iv); // encode return base64_encode($output); } public function decrypt($string, $key = 'PrivateKey', $secret = 'SecretKey', $method = 'AES-256-CBC') { // hash $key = hash('sha256', $key); // create iv - encrypt method AES-256-CBC expects 16 bytes $iv = substr(hash('sha256', $secret), 0, 16); // decode $string = base64_decode($string); // decrypt return openssl_decrypt($string, $method, $key, 0, $iv); } } $csrf = new csrf_check(); //start example $do = filter_input(INPUT_GET, 'do'); $key = filter_input(INPUT_GET, 'key'); switch ($do) { //example.com?do=get - a key for the request case "get": { $key = $csrf->create_api_key(); echo '<a href="?do=check&key='.urlencode($key).'">Check Key ('.$key.')</a>'; } break; //example.com?do=check - a key for the request case "check": { //key only lasts 30 secs & validate key passed //example.com?do=check&key=MEV6NXk4UjVRQXV5Qm1CMjBYa3RZZUhGd2M0YnFBUVF0ZkE5TFpNaElUTT0= echo 'Key ' . ($csrf->check_api_key($key, 30) ? 'valid' : 'invalid'); echo '<br><a href="?do=get">Get new key</a>'; } break; default: { echo '<a href="?do=get">Get Key</a>'; } break; }