如何创build和使用随机数
我正在运行一个网站,并且有一个评分系统,可以让你知道你玩游戏的次数。
它使用哈希来certificatehttp请求得分的完整性,所以用户不能改变任何东西,但是因为我担心可能发生,有人发现他们不需要改变它,他们只需要得到高分, http请求,标题和所有。
以前我被禁止保护免受这种攻击,因为它被认为不太可能。 但是,现在已经发生了,我可以。 http请求来自flash游戏,然后通过phpvalidation,php将其input到数据库中。
我非常确定随时可以解决这个问题,但我不确定如何实施它们。 什么是build立一个nonce系统的一个通用而安全的方法?
这实际上很容易做…有一些图书馆为你做:
- PHP随机数库
- OpenID 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
真的只需要返回一个随机数字或string。 随机性越好,安全性越好…还要注意,由于它被正确地join到散列函数中,所以从请求到请求的实现细节并不重要。 客户端版本和服务器版本不需要匹配。 实际上,唯一需要匹配100%的是散列函数hash('sha512', $nonce . $cnonce . $data);
使用的散列函数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; }
随叫随到是一jar蠕虫。
不,实际上,几个CAESAR条目的动机之一就是devise一个经过authentication的encryptionscheme,最好是基于stream密码,这样可以防止随机重复使用。 (例如,使用AES-CTR重复使用随机数,可以消除第一年编程的学生可以解密的信息的机密性。)
有三个主要的思想stream派:
- 在对称密钥encryption中:使用递增的计数器,同时注意不要重复使用它。 (这也意味着为发送者和接收者使用一个单独的计数器。)这需要有状态编程(即,在某处存储该随机数,使得每个请求不从
1
开始)。 - 有状态随机随机数。 生成随机随机数,然后记住它以后再validation。 这是用来击败CSRF攻击的策略,这听起来更接近于这里所要求的。
- 大型无状态随机随机数。 给定一个安全的随机数发生器,几乎可以保证在你的有生之年不会重复一次随机数。 这是NaCl用于encryption的策略。
因此,考虑到这一点,要提出的主要问题是:
- 上述哪一种思想与您正在努力解决的问题最相关?
- 你是如何产生现时?
- 你如何validation现时?
生成一个随机数
对于任何随机随机,问题2的答案是使用CSPRNG。 对于PHP项目,这意味着:
-
random_bytes()
为PHP 7 +项目 - paragonie / random_compat ,一个用于
random_bytes()
的PHP 5 polyfill - ircmaxell / RandomLib ,这是随机性公用事业的瑞士军刀,大多数处理随机性的项目(例如fir密码重置)应该考虑使用,而不是滚动自己的
这两个在道德上是等同的:
$factory = new RandomLib\Factory; $generator = $factory->getMediumStrengthGenerator(); $_SESSION['nonce'] [] = $generator->generate(32);
和
$_SESSION['nonce'] []= random_bytes(32);
validation一个现时
有状态
有状态的随机数很容易推荐:
$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]);
随意用数据库或memcached查找等来replacearray_search()
。
无状态(这里是龙)
这是一个难以解决的问题:您需要某种方法来防止重播攻击,但是每个HTTP请求之后,您的服务器都会有完全失忆症。
唯一明智的解决scheme是validation到期date/时间,以尽量减less重放攻击的有用性。 例如:
// 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令牌的不符合标准的变体。
一个选项(我在评论中提到)是录制游戏并在安全的环境中重放。
另一件事情是随机或在某些特定的时间logging一些看起来无害的数据,然后在服务器上使用它来validation它(比如突然生活从1%到100%,或者从1到1000分数,表示作弊)。 有了足够的数据,骗子可能试图伪造它是不可行的。 然后当然实施重磅禁令:)。
防止作弊是不可能的。 你只能让它变得更加困难。
如果有人来这里寻找PHP Nonce Library:我build议不要使用ircmaxwell给出的第一个 。
网站上的第一个评论描述了一个devise缺陷:
随机数对于一个特定的时间窗是有利的,即,用户越接近该窗的尽头,他或她必须提交表格的时间越less,可能less于一秒
如果您正在寻找一种生成定义明确的生命周期的方法,请查看NonceUtil-PHP 。