ChatGPT解决这个技术问题 Extra ChatGPT

如何创建和使用随机数

我正在运营一个网站,并且有一个评分系统,可以根据您玩游戏的次数为您提供积分。

它使用散列来证明http请求评分的完整性,因此用户无法更改任何内容,但是正如我担心可能发生的那样,有人发现他们不需要更改它,他们只需要获得高分,然后复制http请求,标头和所有。

以前我被禁止防御这种攻击,因为它被认为不太可能。但是,既然已经发生了,我可以。 http请求来源于flash游戏,经过php验证,php进入数据库。

我很确定 nonces 会解决这个问题,但我不确定如何实现它们。什么是设置 nonce 系统的常见且安全的方法?

请注意,Flash 游戏在您的客户端上所做的任何事情都可以由具有反编译器/数据包嗅探器和足够时间的人复制。因此,您添加的任何保护都可能被击败。
这是我有兴趣增加错误地计算的时间。是的,他们可以反编译并替换它,但散列算法不是秘密,只是因为它有一个秘密盐而受到保护,如果他们很聪明,他们可以用彩虹表找出答案。
这就是发明禁锤的原因。
@cdhowie - 并非如此,您可以录制游戏玩法,然后在服务器上重播,然后从重播中获得分数,简而言之。虽然编码恐怖;)。
Maurycy:这不会阻止一遍又一遍地重玩同一场比赛。它也不会阻止人们实现自己的游戏记录生成器。

E
EasyCo

这实际上很容易做到......有一些图书馆可以为你做这件事:

PHP Nonce 库 OpenID Nonce 库

或者如果你想自己写,这很简单。使用 WikiPedia page 作为起点,在伪代码中:

在服务器端,您需要两个客户端可调用函数

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

好的答案,但生成一个随机数然后通过 http(即开放线路)传输并不能防止重放攻击。 “你能信任客户吗”这个古老的问题,答案总是“不”。除非您有服务器端会话逻辑,否则这很难。
@zebrabox,Nonce 可以防止重放攻击。随机数是“仅使用一次的数字”,因此您只需维护以前使用的随机数的列表,并拒绝任何使用随机数两次的尝试。
被否决是因为链接库 FT-Nonce 在生成唯一密钥时非常不安全。
创建 $id 的逻辑是什么?如果我们使用会话,需要将会话 ID 传递给客户端,客户端将会话 ID 发送回服务器以识别正在使用的随机数?
S
Scott Arciszewski

随机数是一罐蠕虫。

不,实际上,多个 CAESAR 条目的动机之一是设计一种经过身份验证的加密方案,最好基于流密码,以防止随机数重用。 (例如,使用 AES-CTR 重用 nonce 会破坏消息的机密性,以至于一年级编程学生可以解密它。)

随机数主要分为三种思想流派:

在对称密钥加密中:使用递增的计数器,同时注意不要重复使用它。 (这也意味着对发送者和接收者使用单独的计数器。)这需要有状态的编程(即将随机数存储在某个地方,这样每个请求就不会从 1 开始)。有状态的随机数。生成一个随机 nonce,然后记住它以供以后验证。这是用来击败 CSRF 攻击的策略,听起来更接近这里的要求。大型无状态随机随机数。给定一个安全的随机数生成器,你几乎可以保证在你的一生中永远不会重复一次随机数。这是 NaCl 用于加密的策略。

因此,考虑到这一点,要问的主要问题是:

上述哪些思想流派与您要解决的问题最相关?你是如何产生随机数的?你如何验证随机数?

生成随机数

对于任何随机 nonce,问题 2 的答案是使用 CSPRNG。对于 PHP 项目,这意味着以下之一:

用于 PHP 7+ 项目的 random_bytes()

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);

验证 Nonce

有状态的

有状态的随机数很容易并推荐:

$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 的不符合标准的变体。


你不能通过将随机数写入数据库来防止重放攻击,当它被“赎回”时,你不能将它从数据库中删除吗?因此,采用您的“有状态”方法,并将 $_SESSION['nonces'] 替换为将 nonce 链接到用户名(可能还有超时)的 nonces 表?
这就是我们所做的,但有一个过期列,因此我们可以限制生命周期并清除放弃的 SSO 尝试。
M
Maurycy

一种选择(我在评论中提到)是录制游戏并在安全的环境中重播。

另一件事是随机,或者在特定的时间,记录一些看似无辜的数据,以后可以在服务器上进行验证(比如突然直播从1%到100%,或者从1到1000分表示作弊)。有了足够的数据,作弊者试图伪造它可能是不可行的。然后当然实施严厉禁止:)。


o
oleviolin

这个非常简单的随机数每 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 可以是过程中使用的任何函数调用或用户名等。


R
Raniz

无法防止作弊。你只能让它变得更加困难。

如果有人来这里寻找 PHP Nonce 库:我建议不要使用 the first one given by ircmaxwell

网站上的第一条评论描述了一个设计缺陷:

随机数适用于某个时间窗口,即用户越接近该窗口的末尾,他或她提交表单的时间就越少,可能不到一秒

如果您正在寻找一种方法来生成具有明确定义的生命周期的 Nonce,请查看 NonceUtil-PHP

免责声明:我是 NonceUtil-PHP 的作者


您能否确认这个一年多前编写的实用程序仍然是一个不错的选择?
@NathanArthur 如果您查看作者,那是 Timo 本人。他的 NonceUtil.php 使用 sha-1,不检查以前的 nonce,并且有一个硬编码的盐字符串...... ircmaxwell 的答案中列出的第一个库使用 md5,第二个使用简单的 rand 来创建 nonce。即没有使用sha256/sha512。但是,如果 nonce 的目标只是拥有一个不可重复的字符串,那么您只需要一个好的随机生成器(例如:openssl_random_pseudo_bytes)然后存储生成的随机生成器以便在使用它们之前进行检查。
我不会推荐目前实施的 NonceUtil。