随机数是一罐蠕虫。
不,实际上,几个CAESAR条目的动机之一是设计一种经过身份验证的加密方案,最好基于流密码,它可以抵抗 nonce 重用。(例如,使用 AES-CTR 重用 nonce 会破坏消息的机密性,以至于一年级编程学生可以解密它。)
随机数主要分为三种思想流派:
- 在对称密钥加密中:使用递增的计数器,同时注意不要重复使用它。(这也意味着对发送者和接收者使用单独的计数器。)这需要有状态的编程(即将随机数存储在某个地方,这样每个请求就不会从 开始
1
)。
- 有状态的随机数。生成一个随机 nonce,然后记住它以供以后验证。这是用来击败 CSRF 攻击的策略,听起来更接近这里的要求。
- 大型无状态随机随机数。给定一个安全的随机数生成器,你几乎可以保证在你的一生中永远不会重复一次随机数。这是NaCl用于加密的策略。
因此,考虑到这一点,要问的主要问题是:
- 上述哪些思想流派与您要解决的问题最相关?
- 你是如何产生随机数的?
- 你如何验证随机数?
生成随机数
对于任何随机 nonce,问题 2 的答案是使用 CSPRNG。对于 PHP 项目,这意味着以下之一:
这两个在道德上是等价的:
$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的不符合标准的变体。