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

Как создавать и использовать nonces

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

Он использует хэширование, чтобы доказать целостность HTTP-запроса для подсчета очков, чтобы пользователи ничего не могли изменить, однако, как я боялся, может случиться, кто-то понял, что им не нужно его менять, им просто нужно было получить высокий балл, и дублировать http-запрос, заголовки и все.

Раньше мне было запрещено защищать от этой атаки, потому что это считалось маловероятным. Однако теперь, когда это произошло, я могу. HTTP-запрос берется из флеш-игры, а затем проверяется php и php вносит его в базу данных.

Я уверен, что nonces решит проблему, но я не совсем уверен, как ее реализовать. Что такое обычный и безопасный способ настройки системы nonce?

4b9b3361

Ответ 1

Это на самом деле довольно легко сделать... Есть несколько библиотек, чтобы сделать это для вас:

  1. PHP Nonce Library
  2. OpenID Nonce Library

Или, если вы хотите написать свой собственный, это довольно просто. Использование страницы WikiPedia в качестве отправной точки, в псевдокоде:

На стороне сервера вам нужны две вызываемые клиентом функции

getNonce() {
    $id = Identify Request //(either by username, session, or something)
    $nonce = hash('sha512', makeRandomString());
    storeNonce($id, $nonce);
    return $nonce to client;
}

verifyNonce($data, $cnonce, $hash) {
    $id = Identify Request
    $nonce = getNonce($id);  // Fetch the nonce from the last request
    removeNonce($id, $nonce); //Remove the nonce from being used again!
    $testHash = hash('sha512',$nonce . $cnonce . $data);
    return $testHash == $hash;
}

И на стороне клиента:

sendData($data) {
    $nonce = getNonceFromServer();
    $cnonce = hash('sha512', makeRandomString());
    $hash = hash('sha512', $nonce . $cnonce . $data);
    $args = array('data' => $data, 'cnonce' => $cnonce, 'hash' => $hash);
    sendDataToClient($args);
}

Функция makeRandomString действительно просто должна возвращать случайное число или строку. Чем лучше случайность, тем лучше защита... Также обратите внимание, что, поскольку она передается прямо в хэш-функцию, детали реализации не имеют значения от запроса к запросу. Версия клиента и версия сервера не должны совпадать. Фактически, единственный бит, который должен соответствовать 100%, - это хеш-функция, используемая в hash('sha512', $nonce. $cnonce. $data);... Вот пример довольно безопасной функции makeRandomString...

function makeRandomString($bits = 256) {
    $bytes = ceil($bits / 8);
    $return = '';
    for ($i = 0; $i < $bytes; $i++) {
        $return .= chr(mt_rand(0, 255));
    }
    return $return;
}

Ответ 2

Nonces - это банда червей.

Нет, действительно, одной из мотиваций для нескольких CAESAR было создание схемы аутентифицированного шифрования, предпочтительно основанной на поточном шифре, которая устойчива к nonce повторное использование. (Повторное использование nonce с AES-CTR, например, уничтожает конфиденциальность вашего сообщения до степени, когда первый год студент может расшифровать его.)

Существуют три основные школы мысли с несами:

  • В криптографии с симметричным ключом: используйте увеличивающий счетчик, не обращая внимания на его повторное использование. (Это также означает использование отдельного счетчика для отправителя и получателя.) Для этого требуется программирование с сохранением состояния (т.е. Где-то сохранено значение nonce, поэтому каждый запрос не начинается с 1).
  • Состояния случайных случайных. Создание случайного nonce, а затем запоминание его для подтверждения позже. Это стратегия, используемая для поражения атак CSRF,, которая звучит ближе к тому, что предлагается здесь.
  • Большие случайные символы без атак. Учитывая надежный генератор случайных чисел, вы можете почти гарантировать, что никогда не повторяйте nonce дважды в своей жизни. Это стратегия, используемая NaCl для шифрования.

Итак, имея в виду, основные вопросы, которые нужно задать, следующие:

  • Какая из вышеупомянутых школ мысли наиболее важна для проблемы, которую вы пытаетесь решить?
  • Как вы генерируете nonce?
  • Как вы проверяете nonce?

Создание Nonce

Ответ на вопрос 2 для любого случайного nonce заключается в использовании CSPRNG. Для проектов PHP это означает одно из:

  • random_bytes() для проектов с PHP 7+
  • paragonie/random_compat, PHP 5 polyfill для random_bytes()
  • ircmaxell/RandomLib, который является швейцарским армейским ножом утилит случайности, который в большинстве проектов, которые имеют дело с случайностью (например, сбрасывание пароля), должен рассмотреть возможность использования вместо того, чтобы собственный

Эти два являются морально эквивалентными:

$factory = new RandomLib\Factory;
$generator = $factory->getMediumStrengthGenerator();
$_SESSION['nonce'] [] = $generator->generate(32);

и

$_SESSION['nonce'] []= random_bytes(32);

Проверка несовместимости

Stateful

Простые и рекомендуемые высказывания:

$found = array_search($nonce, $_SESSION['nonces']);
if (!$found) {
    throw new Exception("Nonce not found! Handle this or the app crashes");
}
// Yay, now delete it.
unset($_SESSION['nonce'][$found]);

Не забудьте заменить array_search() на поиск базы данных или memcached и т.д.

Без гражданства (здесь будут драконы)

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

Единственным разумным решением будет аутентификация даты/времени истечения срока действия, чтобы свести к минимуму эффективность повторных атак. Например:

// Generating a message bearing a nonce
$nonce = random_bytes(32);
$expires = new DateTime('now')
    ->add(new DateInterval('PT01H'));
$message = json_encode([
    'nonce' => base64_encode($nonce),
    'expires' => $expires->format('Y-m-d\TH:i:s')
]);
$publishThis = base64_encode(
    hash_hmac('sha256', $message, $authenticationKey, true) . $message
);

// Validating a message and retrieving the nonce
$decoded = base64_decode($input);
if ($decoded === false) {
    throw new Exception("Encoding error");
}
$mac = mb_substr($decoded, 0, 32, '8bit'); // stored
$message = mb_substr($decoded, 32, null, '8bit');
$calc = hash_hmac('sha256', $message, $authenticationKey, true); // calcuated
if (!hash_equals($calc, $mac)) {
    throw new Exception("Invalid MAC");
}
$message = json_decode($message);
$currTime = new DateTime('NOW');
$expireTime = new DateTime($message->expires);
if ($currTime > $expireTime) {
    throw new Exception("Expired token");
}
$nonce = $message->nonce; // Valid (for one hour)

Тщательный наблюдатель заметит, что это в основном нестандартный вариант JSON Web Tokens.

Ответ 3

Один из вариантов (который я упомянул в комментарии) - это запись игрового процесса и воспроизведение его в защищенной среде.

Другое дело - случайным образом или в определенное время записывать некоторые, казалось бы, невинные данные, которые позже могут быть использованы для проверки его на сервере (например, внезапно живое идет от 1% до 100% или оценивается от 1 до 1000 которые указывают на чит). При наличии достаточного количества данных мошеннику может быть нецелесообразно пытаться подделать его. И тогда, конечно, реализуйте тяжелое запрещение:).

Ответ 4

Этот очень простой одноразовый номер меняется каждые 1000 секунд (16 минут) и может использоваться для предотвращения XSS, когда вы публикуете данные в одном приложении и из него. (Например, если вы находитесь в одностраничном приложении, в котором вы публикуете данные с помощью javascript. Обратите внимание, что вы должны иметь доступ к одному и тому же генератору семени и одноразовых номеров с поста и получателя)

function makeNonce($seed,$i=0){
    $timestamp = time();
    $q=-3; 
    //The epoch time stamp is truncated by $q chars, 
    //making the algorthim to change evry 1000 seconds
    //using q=-4; will give 10000 seconds= 2 hours 46 minutes usable time

    $TimeReduced=substr($timestamp,0,$q)-$i; 

    //the $seed is a constant string added to the string before hashing.    
    $string=$seed.$TimeReduced;
    $hash=hash('sha1', $string, false);
    return  $hash;
}   

Но проверяя предыдущий одноразовый номер, пользователь будет обеспокоен, только если он подождет более 16,6 минут в худшем случае и 33 минуты в лучшем случае. Установка $ q = -4 даст пользователю минимум 2,7 часа

function checkNonce($nonce,$seed){
//Note that the previous nonce is also checked giving  between 
// useful interval $t: 1*$qInterval < $t < 2* $qInterval where qInterval is the time deterimined by $q: 
//$q=-2: 100 seconds, $q=-3 1000 seconds, $q=-4 10000 seconds, etc.
    if($nonce==$this->makeNonce($seed,0)||$nonce==$this->makeNonce($seed,1))     {
         //handle data here
         return true;
     } else {
         //reject nonce code   
         return false;
     }
}

$ Seed может быть любым вызовом функции или именем пользователя и т.д., Используемыми в процессе.

Ответ 5

Невозможно предотвратить обман. Вы можете только сделать это более сложным.

Если кто-то пришел сюда в поисках библиотеки Nonce PHP: я не рекомендую использовать первую, предоставленную ircmaxwell.

Первый комментарий на сайте описывает недостаток дизайна:

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

Если вы ищете способ генерировать одноразовые номера с четко определенным временем жизни, взгляните на NonceUtil-PHP.

Отказ от ответственности: я являюсь автором NonceUtil-PHP