11

これがトークンを設定するための安全な方法であるかどうか疑問に思っています。実際にトークンが生成されない限り、トークンを生成して、アプリケーションとそれらのフォーム全体で使用します。セッションごとに1つのトークン?

if (!isset($_SESSION['token'])) {
    $data['token'] = uniqid(rand(), true);
    session_regenerate_id();
    $_SESSION['token'] = $data['token'];
}

送信されたフォームのトークンをクリアする必要がありますか?または、フォームを送信したにもかかわらず、そのままにしますか?

4

6 に答える 6

11

これらのリンクがわからない場合は、いくつかのシナリオを理解するのに役立ちます。具体的には、これにより、すべきこととすべきでないことがわかります。それが役に立てば幸い。

于 2012-12-09T18:53:38.093 に答える
10

個人的には、表示したいフォームごとに新しいトークンを生成します。このようにすると、誰かがあなたのトークンを読み取り、セッションがアクティブである限りそれを使用するためにセッションCookieが必要になります。

私のアプリケーションでは、次のようにフォーム表示ごとにトークンを生成します。

<?php
$token = uniqid(rand(), true);
$_SESSION['csrf_tokens'][$token] = true;

HTML

<form>
    <input type="hidden" name="token" value="<?php echo $token ?>" />
</form>

フォームの検証時に、次のようにそのトークンをチェックします。

if (isset($_SESSION['csrf_tokens'][$token]) && $_SESSION['csrf_tokens'][$token] === true) {
    unset($_SESSION['csrf_tokens'][$token]);
    // additional code here
}
于 2012-12-09T18:08:03.710 に答える
2

per-session token私はセキュリティを強化するために使用するよりも、最も安全であるが使いやすさに影響を与えるper-form/url tokenと主張する人もいるかもしれません。per-request token

また、セッションストレージをトークンストレージから分離し、のようなものを使用する方が良いと思いますMemcacheexpiration to the token これは、複数のアプリケーションサーバーなどを使用して速度が必要な場合に適しています。全体に影響を与えることなくカスタムを追加できるので、私もそれを好みます。session

これが典型的な例です

HTML

<form method="POST" action="#">
    IP:<input type="text" name="IP" /> <input type="hidden" name="token"
        value="<?php echo Token::_instance()->generate(); ?>" /> <input
        type="Submit" value="Login" />
</form>

処理

$id = "id44499900";
Token::_instance()->initialise($id); // initialise with session ID , user ID or IP

try {

    Token::_instance()->authenticate();
    // Process your form
} catch ( TokenException $e ) {
    http_response_code(401); // send HTTP Error 401 Unauthorized
    die(sprintf("<h1>%s</h1><i>Thief Thief Thief</i>", $e->getMessage()));
}

使用したクラス

class Token {
    private $db;
    private $id;
    private static $_instance;

    function __construct() {
        $this->db = new Memcache();
        $this->db->connect("localhost");
    }

    public static function _instance() {
        self::$_instance === null and self::$_instance = new Token();
        return self::$_instance;
    }

    public function initialise($id) {
        $this->id = $id;
    }

    public function authenticate(array $source = null, $key = "token") {
        $source = $source !== null ? $source : $_POST;

        if (empty($this->id)) {
            throw new TokenException("Token not Initialised");
        }

        if (! empty($source)) {
            if (! isset($source[$key]))
                throw new TokenException("Missing Token");
            if (! $this->get($this->id . $source[$key])) {
                throw new TokenException("Invalid Token");
            }
        }
    }

    public function get($key) {
        return $this->db->get($key);
    }

    public function remove($key) {
        return $this->db->delete($key);
    }

    public function generate($time = 120) {
        $key = hash("sha512", mt_rand(0, mt_getrandmax()));
        $this->db->set($this->id . $key, 1, 0, $time);
        return $key;
    }
}
class TokenException extends InvalidArgumentException {
}

注:トークンは120秒後に自動的に削除され、ユーザーフレンドリーな機能に影響を与える可能性があるため、この例は[戻る]ボタンまたは更新に影響を与える可能性があることに注意してください

于 2012-12-31T13:30:19.853 に答える
2

これがトークンを設定するための安全な方法かどうか疑問に思います

これは、Webアプリの安全性によって異なります。この行は暗号的に安全ではありません(uniqid()およびrand()のPHPドキュメントで警告されているように):

uniqid(rand(), true);

トークンの生成時刻が既知/決定されており、rand()シードが既知/決定されている場合、攻撃者がこれを決定/ブルートフォースする可能性があります。ただし、攻撃者がトークン値を知らない場合でもCSRF攻撃を防ぐことができるため、目的には問題がない場合があります。

セッションごとに1つのトークン?

セッションごとに1つのトークンを使用することは、目的に適している場合があります。ただし、次の点に注意してください。

  1. セッションの長さがn分である場合、攻撃者はn分のウィンドウを使用して、トークン値を決定または取得し、CSRF攻撃を実行しようとします。一方、トークンがフォームごとに生成される場合、またはトークンの寿命が十分でないためにトークンが定期的に再生成される場合、このリスクは軽減されます。
  2. セッションごとに1つのトークンを使用すると、攻撃者がトークンを特定/取得した場合に、アプリケーションのすべての機能(そのトークンを使用する)が攻撃にさらされます。一方、フォームごとにトークンを使用すると、攻撃は単一のフォームに制限されます。

提出されたフォームのトークンをクリアする必要がありますか?または、フォームを送信したにもかかわらず、そのままにしますか?

これは、アプリケーションが攻撃者にとってどれほど高い価値を持っているか、および攻撃によって引き起こされる混乱のレベルによって異なります。既存の対策ではCSRF攻撃の実行が困難になりますが、それが価値が高く、攻撃者を決定的に決定している場合は、次の方法でCSRFのリスクをさらに減らすことができます。

  1. 暗号的に安全なトークンを使用して、トークン値を決定したりブルートフォースしたりするリスクを防ぎます。
  2. トークンを定期的に再生成してトークンの寿命を縮め、トークンが決定または取得された場合の攻撃ウィンドウを減らします。
  3. フォームごとにトークンを生成して、トークンが決定または取得された場合に攻撃を単一のフォームに制限します。
于 2013-01-02T04:42:04.713 に答える
1

私はすでに別のフォーラムで同様の質問に答えました:ここ。うまくいけば、それがお役に立てば幸いです。CSRF防止の基本的なプロセスを説明し、CSRFフレームワークのコードへのリンクを示します。

より高いセキュリティが必要な場合は、各セッションの各リクエストの後にトークンを変更してください。使いやすさを向上させたい場合は、セッションごとに1つのトークンを保持します。

于 2013-01-14T14:09:14.363 に答える
1

次のサイトを参照してください、これはいくつかのアイデアを得るかもしれません。

1.)https://docs.djangoproject.com/en/dev/ref/contrib/csrf/

2.)http://blog.whitehatsec.com/tag/session-token/

返信ありがとうございます。

于 2013-01-05T11:13:09.487 に答える