2

私は自分の目的のために何かを見つけようとして多くのことを検索しましたが、ほとんどのソリューションは、セッション データと連携して機能する CSRF トークンを中心に展開しています。私の目的には、クロスサーバー通信用の「時間ベース」のトークンが必要です。

Server Aから POST 経由で送信されたトークンを受信して​​検証する必要がありますServer BServer Bトークンは、秘密鍵でハッシュして生成する必要があります。Server A同じことを検証する必要があります。ここでの問題は、トークンを 1 回限りの使用 (おそらく?) に制限する必要があり、時間に基づいて期限切れにする必要があることです (たとえば、10 分の有効期間)。これはクロスサーバー通信なので、セッションは使えません。

残念ながら、データベースまたはセッションを使用してトークンを保存/検証することはできません。コードサンプルは役に立ちます。

これは PHP 環境で必要です。

4

1 に答える 1

4

トークンキーにタイムスタンプを追加して、作成時とリクエスター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;
}
于 2012-06-18T14:50:30.637 に答える