PHP - коды URI Google Authenticator не всегда работают

Так что у меня проблема с аутентификатором Google и моим PHP.

Поэтому я использую эту библиотеку для создания QR-кодов: https://github.com/PHPGangsta/GoogleAuthenticator

Поэтому, когда я использую свое имя пользователя для генерации кода, он работает нормально. Я получаю что-то вроде: otpauth://totp/username? Secret=aCodeInBase32&isser=Mysite

Для моего случая это: otpauth://totp/NoahNok? Secret=aCodeInBase32&isser=JukeHost

однако, делая это для любого другого использования, я получаю неверную ошибку токена в приложении Google Authenticator. Неважно, что еще я положил, я всегда получаю эту ошибку, но она отлично работает для моей учетной записи.

Например, этот не работает: otpauth://totp/Test? Secret=KRSX& эмитент = JukeHost

Есть что-то очевидное, что я делаю неправильно?

Код, который я использую: некоторые запросы, прежде чем получить данные

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

Создает 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.'';
}

1 ответ

Решение

Base32 дополняется до ближайшего кратного из 8 символов, поэтому не всегда ==== в конце раздеться. Из ваших примеров мы получаем:

NoahNok => JZXWC2CON5VQ====

а также:

Test => KRSXG5A=

Поэтому, если вы удаляете последние 4 символа всегда, вы создадите недопустимую последовательность Base32 для ситуаций, подобных последним. Вы могли бы вместо этого использовать rtrim вот так:

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

просто удалить все конечные равные (или просто оставить их в).

редактировать

Я просто думал об этом, и хотя вышеизложенное исправит ближайшую проблему, генерация секрета таким образом, вероятно, не очень хорошая идея. Если вы думаете об этом, установка секретного значения равным имени пользователя означает, что если кто-то найдет имя пользователя, он может сгенерировать действительный OTP и, следовательно, сможет передать свой 2FA.

Секрет должен быть уникальным и, как правило, неосуществимым для этой цели, а используемая вами библиотека имеет createSecret способ сделать это для вас.

Другие вопросы по тегам