PHP - Google 身份验证器 URI 代码并不总是有效
PHP - Google Authenticator URI codes don't always work
所以我在使用 google 验证器和我的 PHP 时遇到了问题。
所以我正在使用这个库生成二维码:https://github.com/PHPGangsta/GoogleAuthenticator
因此,当我使用我的用户名生成代码时,它工作正常。我得到一些类似的东西:
otpauth://totp/username?secret=aCodeInBase32&issuer=Mysite
对于我的情况是:
otpauth://totp/NoahNok?secret=aCodeInBase32&issuer=Mysite
然而,当为任何其他用途执行此操作时,我在 Google Authenticator 应用程序上收到无效令牌错误。不管我放什么,我似乎总是收到此错误,但它对我的帐户来说工作正常。
例如这个不起作用:otpauth://totp/Test?secret=KRSX&issuer=MySite
我有什么明显的错误吗?
我使用的代码:
获取数据之前的一些查询
$g = new PHPGangsta_GoogleAuthenticator();
include("Base32.php");
$secret = substr(Base32::encode($username),0,-4);
echo $g->getQRCodeGoogleUrl($username, $secret, "MySite");
生成二维码URL
public function getQRCodeGoogleUrl($name, $secret, $title = null, $params = array())
{
$width = !empty($params['width']) && (int) $params['width'] > 0 ? (int) $params['width'] : 200;
$height = !empty($params['height']) && (int) $params['height'] > 0 ? (int) $params['height'] : 200;
$level = !empty($params['level']) && array_search($params['level'], array('L', 'M', 'Q', 'H')) !== false ? $params['level'] : 'M';
$urlencoded = urlencode('otpauth://totp/'.$name.'?secret='.$secret.'');
if (isset($title)) {
$urlencoded .= urlencode('&issuer='.urlencode($title));
}
return 'https://chart.googleapis.com/chart?chs='.$width.'x'.$height.'&chld='.$level.'|0&cht=qr&chl='.$urlencoded.'';
}
Base32 被填充到最接近的 8 个字符的倍数,所以它不会总是在末尾有 ====
来剥离。从您的示例中我们得到:
NoahNok => JZXWC2CON5VQ====
和:
Test => KRSXG5A=
因此,如果您始终删除最后 4 个字符,您将在类似后者的情况下创建无效的 Base32 序列。您可以像这样使用 rtrim
:
$secret = rtrim(Base32::encode($username), '=')
只删除所有尾随的等号(或只保留它们)。
编辑
我只是在考虑这个,虽然上面的方法可以解决最接近的问题,但以这种方式生成秘密可能不是一个好主意。如果您考虑一下,将秘密设置为用户名意味着如果有人找到用户名,他们可以生成有效的 OTP,因此能够通过他们的 2FA。
Secret 应该是唯一的,并且通常不能被猜到,您正在使用的库有一个 createSecret
方法可以为您做到这一点。
所以我在使用 google 验证器和我的 PHP 时遇到了问题。
所以我正在使用这个库生成二维码:https://github.com/PHPGangsta/GoogleAuthenticator
因此,当我使用我的用户名生成代码时,它工作正常。我得到一些类似的东西: otpauth://totp/username?secret=aCodeInBase32&issuer=Mysite
对于我的情况是: otpauth://totp/NoahNok?secret=aCodeInBase32&issuer=Mysite
然而,当为任何其他用途执行此操作时,我在 Google Authenticator 应用程序上收到无效令牌错误。不管我放什么,我似乎总是收到此错误,但它对我的帐户来说工作正常。
例如这个不起作用:otpauth://totp/Test?secret=KRSX&issuer=MySite
我有什么明显的错误吗?
我使用的代码: 获取数据之前的一些查询
$g = new PHPGangsta_GoogleAuthenticator();
include("Base32.php");
$secret = substr(Base32::encode($username),0,-4);
echo $g->getQRCodeGoogleUrl($username, $secret, "MySite");
生成二维码URL
public function getQRCodeGoogleUrl($name, $secret, $title = null, $params = array())
{
$width = !empty($params['width']) && (int) $params['width'] > 0 ? (int) $params['width'] : 200;
$height = !empty($params['height']) && (int) $params['height'] > 0 ? (int) $params['height'] : 200;
$level = !empty($params['level']) && array_search($params['level'], array('L', 'M', 'Q', 'H')) !== false ? $params['level'] : 'M';
$urlencoded = urlencode('otpauth://totp/'.$name.'?secret='.$secret.'');
if (isset($title)) {
$urlencoded .= urlencode('&issuer='.urlencode($title));
}
return 'https://chart.googleapis.com/chart?chs='.$width.'x'.$height.'&chld='.$level.'|0&cht=qr&chl='.$urlencoded.'';
}
Base32 被填充到最接近的 8 个字符的倍数,所以它不会总是在末尾有 ====
来剥离。从您的示例中我们得到:
NoahNok => JZXWC2CON5VQ====
和:
Test => KRSXG5A=
因此,如果您始终删除最后 4 个字符,您将在类似后者的情况下创建无效的 Base32 序列。您可以像这样使用 rtrim
:
$secret = rtrim(Base32::encode($username), '=')
只删除所有尾随的等号(或只保留它们)。
编辑
我只是在考虑这个,虽然上面的方法可以解决最接近的问题,但以这种方式生成秘密可能不是一个好主意。如果您考虑一下,将秘密设置为用户名意味着如果有人找到用户名,他们可以生成有效的 OTP,因此能够通过他们的 2FA。
Secret 应该是唯一的,并且通常不能被猜到,您正在使用的库有一个 createSecret
方法可以为您做到这一点。