Я запускаю веб-сайт, и есть система подсчета очков, которая дает вам очки за количество раз, когда вы играете в игру.
Он использует хеширование, чтобы доказать целостность HTTP-запроса для подсчета очков, чтобы пользователи ничего не могли изменить, однако, как я боялся, может случиться, кто-то понял, что им не нужно его менять, им просто нужно было получить высокий балл и дублировать http-запрос, заголовки и все.
Раньше мне было запрещено защищать от этой атаки, потому что это считалось маловероятным. Однако теперь, когда это произошло, я могу. HTTP-запрос берется из флеш-игры, а затем проверяется php и php, вводит их в базу данных.
Я уверен, что нонс решит проблему, но я не совсем уверен, как ее реализовать. Что такое обычный и безопасный способ настройки системы nonce?
На самом деле это довольно легко сделать … Для этого есть несколько библиотек:
Или, если вы хотите написать свой собственный, это довольно просто. Использование страницы 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; }
Нет, действительно, одним из мотивов для нескольких записей CAESAR было создание схемы аутентифицированного шифрования, предпочтительно основанной на поточном шифре, которая устойчива к повторному использованию nonce. (Повторное использование nonce с AES-CTR, например, разрушает конфиденциальность вашего сообщения до степени, когда ученик первого курса может расшифровать его.)
Есть три основные школы мысли с нонцами:
1
). Поэтому, имея в виду, основные вопросы:
Ответ на вопрос 2 для любого случайного nonce заключается в использовании CSPRNG. Для проектов PHP это означает одно из:
random_bytes()
для проектов PHP 7+ random_bytes()
Эти двое морально эквивалентны:
$factory = new RandomLib\Factory; $generator = $factory->getMediumStrengthGenerator(); $_SESSION['nonce'] [] = $generator->generate(32);
а также
$_SESSION['nonce'] []= random_bytes(32);
Простые и рекомендуемые высказывания:
$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()
заменить 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('Ymd\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 .
Один из вариантов (который я упомянул в комментарии) – это запись игрового процесса и воспроизведение его в защищенной среде.
Другое дело – случайным образом или в определенное время записывать некоторые, казалось бы, невинные данные, которые позже могут быть использованы для проверки его на сервере (например, внезапное ожидание идет от 1% до 100% или оценка от 1 до 1000, что указывает на чит ). При наличии достаточного количества данных мошеннику может быть нецелесообразно пытаться подделать его. И тогда, конечно, реализуйте тяжелое запрещение :).
Невозможно предотвратить обман. Вы можете только усложнить ситуацию.
Если кто-то пришел сюда, ища библиотеку PHP Nonce: я не рекомендую использовать первый, заданный ircmaxwell .
Первый комментарий на веб-сайте описывает недостаток дизайна:
Функция nonce хороша для одного определенного временного окна, т. Е. Чем ближе пользователь добирается до конца этих окон, тем меньше времени он или она должен отправить в форму, возможно, менее одной секунды
Если вы ищете способ генерации Nonces с четко определенным временем жизни, посмотрите на NonceUtil-PHP .