当前位置:  开发笔记 > 编程语言 > 正文

如何创建和使用nonce

如何解决《如何创建和使用nonce》经验,为你挑选了2个好方法。

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

它使用散列来证明http请求的完整性,因此用户无法改变任何东西,但是我担心可能发生,有人发现他们不需要改变它,他们只需要获得高分,并复制http请求,标题和所有.

以前我被禁止防止这种攻击,因为它被认为是不可能的.但是,既然已经发生了,我可以.http请求源自Flash游戏,然后由php验证并且php将其输入数据库.

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



1> ircmaxell..:

它实际上很容易......有一些库可以帮到你:

    PHP Nonce库

    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实际上只需要返回一个随机数或字符串.随机性越好,安全性越好......还要注意,由于它被直接输入到散列函数中,因此实现细节与请求请求无关.客户端的版本和服务器的版本不需要匹配.实际上,需要匹配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;
}


@zebrabox,Nonces将防止重放攻击.Nonce是"仅使用一次的数字",因此您只需维护以前使用过的nonce列表,并拒绝任何使用nonce两次的尝试.
很好的答案,但生成一个nonce然后通过http(即打开线)传输不能防止重放攻击."你能相信客户"这个古老的问题,答案总是"不".除非你有服务器端会话逻辑,否则这很难.
不推荐使用,是因为链接库FT-Nonce在生成唯一密钥方面非常不安全。

2> Scott Arcisz..:

Nonce是一种蠕虫.

不,实际上,几个CAESAR条目的动机之一是设计一个经过验证的加密方案,最好是基于流密码,它可以抵抗随机数重用.(例如,重复使用带有AES-CTR的随机数,会破坏您的信息的机密性,使第一年编程学生可以解密它.)

有六种主要的思想流派:

    在对称密钥密码术中:使用增加的计数器,同时注意永远不要重复使用它.(这也意味着为发送方和接收方使用单独的计数器.)这需要有状态编程(即将nonce存储在某处,因此每个请求都不会从那里开始1).

    有状态随机的随机数.生成随机nonce,然后记住它以便稍后验证.这是用于击败CSRF攻击的策略,这听起来更接近于此处的要求.

    大型无状态随机nonce.给定一个安全的随机数生成器,您几乎可以保证在您的生命中不会重复两次nonce.这是NaCl用于加密的策略.

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

    上述哪种思想与您试图解决的问题最相关?

    你是如何产生现时的?

    你是如何验证nonce的?

生成一个随机数

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

random_bytes() 适用于PHP 7+项目

paragonie/random_compat,PHP 5 polyfill forrandom_bytes()

ircmaxell/RandomLib,这是瑞士军刀的随机性工具,大多数处理随机性的项目(例如冷杉密码重置)应该考虑使用而不是自己滚动

这两个在道德上是等价的:

$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令牌的非标准兼容变体.


您不能通过将随机数写入数据库来防止重放攻击,并且在“赎回”时将其从数据库中删除吗?因此,采用您的“有状态”方法,并用将随机数链接到用户名(或可能是超时)的随机数表替换$ _SESSION ['nonces']吗?
推荐阅读
小白也坚强_177
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有