首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >令牌身份验证的sodium_crypto_auth_verify与hash_equals

令牌身份验证的sodium_crypto_auth_verify与hash_equals
EN

Stack Overflow用户
提问于 2019-10-24 03:01:27
回答 1查看 102关注 0票数 0

我正在为我大学最后一年的项目构建我自己的小框架,我对这里的最佳实践感到非常困惑。我已经读了很多文章,有一个大致的想法,但一些澄清会更好。

我真的很喜欢PHP中新的钠扩展,但我有点困惑。

我正在创建一个长期持久cookies和密码重置拆分令牌身份验证的东西。

我正在尽可能多地使用using,因为它看起来非常安全,无论它是新的还是没有很好的文档记录。

我正在创建一个像selector:validator这样的拆分令牌。我想要做的基本上是使用选择器来查询数据库,

然后,我想要比较两个散列和散列来自cookie的纯文本版本,然后比较(但后者意味着在某个地方保留一个密钥,这会产生问题)。

我在很多文章中都听说过,尤其是Paragone建议,最好将令牌的散列版本存储在数据库中,而将普通版本存储在cookie或令牌中。这有什么真正的好处吗?

我已经创建了一个简单的令牌类:

代码语言:javascript
复制
class SplitToken extends Token
{

protected $selector;

protected $validator;

function __construct($selector=14, $validator=18)
{
    $this->selector = bin2hex(random_bytes($selector));
    $this->validator = bin2hex(random_bytes($validator));
    $this->key = random_bytes(SODIUM_CRYPTO_AUTH_KEYBYTES);
    $this->tokenHash = sodium_crypto_auth($this->validator, $this->key);
}

public function Set()
{
    $this->token = $this->selector.':'.$this->validator;
    return $this;
}

public function Get()
{
    return $this->token;
}

$sptoken = new SplitToken();
$token = $sptoken->set()->Get();
$dt = new DateTime('+ 2 months');
$expiry = $dt->getTimestamp();
//Gets bin2hex version of validator side of token for DB
$validatorHash = $token->GetValidatorHashHex();
$key = $token->GetKey();

//Store token In DB:
$query = "UPDATE Users SET Selector, Validator, Expiry 
WHERE Selector = :Selector and    Validator = :Validator and Expiry = :Expiry;
$stmt = $pdo->prepare($query);
$stmt->execute(
['Selector' => $token->GetSelector(), 
'Validator' => $validatorHash, 
'Expiry' => $expiry]);

现在临时令牌已在数据库中。现在是设置cookie的时候了(当然,同样的情况也可以应用于具有不同到期时间的PW重置。这里我弄糊涂了,我有两个选择:

选项1:

代码语言:javascript
复制
//Store the hexed version of selector:validator in the cookie (but not hashed)
setcookie('auth_token', $token, $expiry, '/', 'CONST_DOMAIN', true, true);

//Where do I store the key?
//So far I am using JSON fuNCTION which gets key from the folder where it is stored:
$storedKey = Key::GetFromVault('auth_token');

if(isset($_COOKIE['auth_token')){
 $cookie = explode(':', $_COOKIE['auth_token'];

//Gets the User from the DB Where Selector = Selector
 $user = DB::SelectUser($user);
//If User exists
 if($user){
 //*** Checks the Hash separate from the query to avoid timing attack ***
 var_dump(sodium_crypto_auth_verify($user->Validator, $cookie[1], $storedKey);
 }

}

选项2:看起来更简单、更清晰,因为我只是比较两个散列,以后不需要担心键,但这意味着我必须将验证器的散列版本存储在cookie中:

代码语言:javascript
复制
$hashedToken = $token->GetSelector.':'.$token->GetValidatorHashHex();
setcookie('auth_token', $hashedToken, $expiry, '/', 'CONST_DOMAIN', true, true);

//Now On Request:
if(isset($_COOKIE['auth_token')){
 $cookie = explode(':', $_COOKIE['auth_token'];
 $user = DB::SelectUser($user);
 if($user){
 //Checks the Hash separate from the query to avoid timing attack
 var_dump(hash_equals($user->Validator, $cookie[1]);
 }

}

我知道这听起来可能很愚蠢,而且没有太大区别,但在选项1中,我将纯文本令牌与散列版本进行比较,并将其与钠函数进行比较,而在选项2中,我将比较两个散列

如果我用is函数比较相同的两个散列,它会返回false;如果我用hash_equals比较纯文本和散列后的文本,即使散列之前的令牌是相同的,它也会返回false。

所以基本上:

1)这有多大区别吗? 2)我想找到一个简洁的密钥存储解决方案,然后将其纯存储在cookie中,但不确定如何存储

任何建议都将不胜感激。很高兴澄清我的问题谢谢

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2019-10-24 19:13:44

这没有任何区别。

sodium_crypto_auth_verify()所做的是计算散列,并将其与提供的散列进行比较。

只要比较是在恒定的时间内进行的,这和你自己做的没有区别。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/58529456

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档