私はウェブサイトを運営していますが、ゲームをプレイした回数に対してポイントを与えるスコアリングシステムがあります。
ハッシュを使用してスコアリングのhttp要求の整合性を証明するため、ユーザーは何も変更できませんが、誰かがそれを変更する必要はないと考えたため、高スコアを取得し、 HTTPリクエスト、ヘッダーなど。
以前は、この攻撃に対する防御は考えられないため禁止されていました。しかし、それが起こった今、私はできます。 httpリクエストはフラッシュゲームから発信され、phpによって検証され、phpがデータベースに入力します。
Noncesが問題を解決すると確信していますが、それらの実装方法は正確にはわかりません。一回限りのシステムをセットアップする一般的で安全な方法は何ですか?
実際には非常に簡単です...あなたのためにそれを行うためのいくつかのライブラリがあります:
または、独自に記述したい場合は、非常に簡単です。 WikiPediaページ をジャンプオフポイントとして使用して、擬似コードで:
サーバー側では、2つのクライアント呼び出し可能関数が必要です
_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 [〜#〜] エントリの動機の1つは、ナンスの再利用に耐性のある認証済みの暗号化スキームを、できればストリーム暗号に基づいて設計することでした。 (たとえば、AES-CTRでナンスを再利用すると、1年生のプログラミング学生が解読できる程度にメッセージの機密性が破壊されます。)
ノンスには3つの主要な考え方があります。
1
_で開始されないようにノンスをどこかに格納する)。そのため、主な質問は次のとおりです。
ランダムナンスに対する質問2の答えは、CSPRNGを使用することです。 PHPプロジェクトの場合、これは次のいずれかを意味します。
random_bytes()
for PHP 7+プロジェクトrandom_bytes()
のポリフィル)_これら2つは道徳的に同等です。
_$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()
をデータベースや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 の非標準準拠のバリアントであることに気付くでしょう。
1つのオプション(コメントで言及しました)は、ゲームプレイを記録し、安全な環境でリプレイすることです。
もう1つは、ランダムに、または特定の時間に、一見無害なデータを記録し、後でサーバー上でそれを検証するために使用できます(突然ライブが1%から100%になるか、チートを示す1から1000のスコア)。十分なデータがあれば、詐欺師がそれを偽造しようとするのは現実的ではありません。そしてもちろん、重い禁止を実装します:)。
この非常に単純なナンスは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は、プロセスで使用される関数呼び出しやユーザー名などです。