我想知道移动验证器是如何工作的(例如Battle.net,rift,有些银行有一个等等),所以我可以为我自己的网站制作一个(只是为了好玩)。
我理解基本知识:身份验证者拥有与手机相关的代码和与网站相关的代码。用户在网站上输入电话代码。然后可以生成相关的令牌(使用电话和网站代码)。
我只是想知道如何创建令牌。这有标准算法吗?算法如何工作?任何可以执行此类操作的现有PHP库(作为示例)?
答案 0 :(得分:6)
看看Google Authenticator。已经有iPhone,Android和Blackberry应用程序,这是一个既定的协议。
他们已将其实施为open-source PAM module,您可以将其与PECL PAM包一起使用。
有一个pure PHP version,但我没有使用过,所以无法保证。
spec不是那个复杂,所以你可能自己实现它,特别是如果你转换了C模块。与此相关的规范解释了它的全部细节。
编辑:我想回答原来的问题,那是一个RFC,所以它有点标准化,它是一个完全开放的规范,使用它的工具是完全开源的。这些协议称为HOTP和TOTP。前者是基于计数器的HMAC(因此使用第n个密码),而后者是基于时间的(因此密码每30秒循环一次)。
答案 1 :(得分:1)
关于Blizzad Battle.Net身份验证器,您可以在PHP中找到一个开源实现:https://github.com/krtek4/php-bma
该实现用于为Battle.Net提供在线身份验证服务:https://authenticator.me
如果您想为您的网站做类似的事情,那就非常简单了。服务器和客户端部分之间唯一共享的是服务器生成的密钥。因此,当客户端请求新秘密时,只需存储它,您就可以随时计算代码以与发送给您的内容进行比较。
答案 2 :(得分:0)
我实施了一次。我使用带有字符子集的4位数密钥(请注意,可能会混淆可能令人困惑的字符,如0oO和l1L。我使用了4个字符,因为字符集中4位数的潜在空间大于RSA密钥的6位数。
无论如何,我让用户使用他们的用户名和密码登录。如果这是正确的,生成一个密钥并将其发送到手机并将其保存在会话中并向用户显示下一页,这需要输入密钥。用户从手机获取4位数密钥并将其输入页面。然后检查他们针对会话保存的密钥输入的内容,然后就可以了。
有一些方便的功能:使密钥在几分钟后过期,但足够长的文本消息延迟不会使其无法实现。经过一些不好的尝试后让它过期。为用户提供重新发送密钥或发送新密钥的链接。
//pick a random 4 digit string
$chars = "abcdefghjkrstwxyzABCDEFGHJKRSTWXYZ23456789";
$key = "";
for($i=0;$i<4;$i++){
//here, rand is used, but any generator could be used
//to choose the characters.
$key .= $chars[rand(0,strlen($chars)-1)];
}
//save it to the session
$_SESSION['test']['KEY'] = $key;
答案 3 :(得分:0)
如果是我,我会根据以前使用的哈希和常见的现时生成哈希,这个棘手的问题就是让两个系统保持同步。 e.g。
<?php
class otp {
var $salt;
var $previous_hash;
var $user_id;
function __construct($user_id)
{
$this->user_id=$user_id;
list($this->$salt, $this->$previous_hash)
=unserialize(file_get_contents(BASE_PATH . $user_id));
}
function authenticate($submitted_otp)
{
if (!$this->salt) {
// user does not exist
return false;
}
$new_hash=$this->previous_hash;
// allow for the sequence to get out of sync by 5 steps....
for ($x=0; $x<5; $x++) {
$new_hash=md5($this->salt, $new_hash);
if ($new_hash===$submitted_otp) {
$this->update_token($new_hash);
return true;
}
}
// none of the next N iterations of the local password match
return false;
}
function create_user($user_id, $salt, $init_hash)
{
return file_put_contents(BASE_PATH . $user_id, array($salt, $init_hash));
}
function update_token($new_hash)
{
file_put_contents(BASE_PATH . $user_id, array($this->salt, $new_hash));
}
}
当然,在实践中你可能不想使用整个32 char md5哈希(只是,比如前6个字符,并应用清理,例如将'S'更改为'5'等)。