简体   繁体   中英

PHP - Google Authenticator URI codes don't always work

So i'm having a problem with google authenticator and my PHP.

So i'm using this library to generate QR codes: https://github.com/PHPGangsta/GoogleAuthenticator

So when I use my username to generate a code it works fine. I get something along the lines of: otpauth://totp/username?secret=aCodeInBase32&issuer=Mysite

For my case it is: otpauth://totp/NoahNok?secret=aCodeInBase32&issuer=Mysite

however when doing this for any other use I get an invalid token error on the Google Authenticator app. It doesnt matter what else I put I always seem to get this error, yet it works fine for my account.

Eg this one doesn't work: otpauth://totp/Test?secret=KRSX&issuer=MySite

Is there something obvious im doing wrong?

Code im using: Some queries before to get data

$g = new PHPGangsta_GoogleAuthenticator();
include("Base32.php");
$secret = substr(Base32::encode($username),0,-4);
echo $g->getQRCodeGoogleUrl($username, $secret, "MySite");

Generates QR 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 is padded out to the nearest multiple of 8 characters, so it won't always have ==== at the end to strip off. From your examples we get:

NoahNok => JZXWC2CON5VQ====

and:

Test => KRSXG5A=

So if you remove the last 4 characters always you'll create an invalid Base32 sequence for situations like the latter. You could instead use rtrim like so:

$secret = rtrim(Base32::encode($username), '=')

to just remove all trailing equals (or just leave them in).

Edit

I was just thinking about this and while the above will fix the proximate issue, generating the secret this way is probably not a good idea. If you think about it, setting the secret equal to the username means that if someone finds the username they can generate a valid OTP and therefore be able to pass their 2FA.

Secret should be unique and generally unguessable for this purpose, and the library you are using has a createSecret method to do this for you.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM