Подтвердить что ты не робот

Это безопасный способ установить токен CSRF?

Мне интересно, если это безопасный способ установить токен, если на самом деле не создан токен, я его генерирую и использую во всех приложениях и в этих формах. Один токен за сеанс?

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

Было бы необходимо очистить токен от поданной формы? или просто остаться с ним, хотя я представил форму?

4b9b3361

Ответ 1

Если вы не знаете эти ссылки, этот должен помочь вам понять некоторые сценарии, а именно расскажут вам ДО и DONT. Надеюсь, что это поможет.

Ответ 2

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

В моих приложениях я генерирую токен для каждого отображения формы следующим образом:

<?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
}

Ответ 3

Вместо использования per-session token я бы предпочел per-form/url token для дополнительной безопасности, некоторые могут утверждать, что per-request token наиболее защищен, но влияет на удобство использования.

Я также считаю, что лучше отделить хранилище сеансов от хранилища токенов и использовать что-то вроде Memcache. Это лучше, когда вам нужна скорость с использованием нескольких серверов приложений и т.д. Я также предпочитаю это, потому что я могу добавить пользовательский expiration 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 секунд, и это может повлиять на удобство использования

Ответ 4

Мне интересно, безопасный ли способ установить токен

Это зависит от того, насколько безопасно ваше веб-приложение. Эта строка не криптографически защищена (как указано в документах PHP для uniqid() и rand()):

uniqid(rand(), true);

Для злоумышленника может быть возможно определить/перебор силы, если время генерации токена известно/определено, а семя rand() известно/определено. Однако для ваших целей это может быть хорошо, поскольку оно все равно предотвратит атаки CSRF, если злоумышленник не знает значения маркера.

Один токен за сеанс?

Использование одного токена за сеанс может быть прекрасным для ваших целей. Однако имейте в виду:

  • Если сеанс длится n минут, злоумышленник имеет n-минутное окно, чтобы попытаться определить или получить значение маркера и выполнить атаку CSRF. В то время как этот риск уменьшается, когда токены генерируются в форме или когда токен периодически регенерируется, поскольку они недостаточно долговечны.
  • Использование одного токена за сеанс предоставляет все возможности вашего приложения (использующего этот токен) для атаки, если злоумышленник определит/получит токен. В то время как использование токена в форме ограничивает атаку в одной форме.

Будет ли необходимость вычищать токен в поданной форме? или просто остаться с ним, хотя я представил форму?

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

  • Использование криптографически защищенных токенов во избежание риска определения или грубой форсировки значения маркера.
  • Периодически регенерирует токен, чтобы сократить срок службы токенов, уменьшая окно атаки, если токен определен или получен.
  • Создание токенов в форме для ограничения атак одной формы в случае определения или получения токена.

Ответ 6

Я уже ответил на аналогичный вопрос на другом форуме: здесь. Надеюсь, это полезно. В нем объясняется основной процесс предотвращения CSRF и ссылки на некоторый код для структуры CSRF.

Если вам нужна более высокая безопасность, измените токен после каждого запроса для каждого сеанса. Если вы хотите улучшить удобство использования, сохраните один токен за сеанс.