Google Authenticator на устройствах Apple, некоторые секреты не действительны

Мы включили двухфакторную аутентификацию в одно из наших приложений с помощью Google Authenticator. В QA появилось что-то действительно странное. Хотя мне удалось это исправить, я не совсем уверен, почему это исправление работает.

Для нашего общего секрета мы присвоили GUID пользователю, когда он начинает настройку TFA. GUID получает кодирование base-32 и помещает его в URL-адрес, который преобразуется в QR-код и сканируется пользователем с помощью телефона:

 otpauth://totp/myapp_user?secret=g5swmnddhbtggllbgi3dsljumi3tallbmuytgljtg5sdgnbxmy2dgyjwmy======

И все работает хорошо для всех не-ios машин, которые мы пробовали. Только на ios он выдает действительно странную ошибку при попытке сканирования штрих-кода большую часть времени:

Invalid barcode

The barcode '[same as above]' is not a valid authentication token barcode.

Он соответствует минимальному секретному требованию Google/RFC 4226 (128 бит), правильно закодирован в Base32 и т. Д. Почему происходит сбой? Типичная причина этого сообщения - пробел в URL - но его нет.

Если я добавлю небольшое начальное число в начало руководства, все будет работать нормально:

otpauth://totp/myapp_user?secret=nfygq33omvzxky3lom3ggmzyha2tgnjnmu4gezbngqzdgyrnhbtdqzrnmeywimrwmjsgknzymi3a

По сути, это разница между:

 secret = enc.Encode32(Encoding.ASCII.GetBytes("iphonesucks" + Guid.NewGuid().ToString()));  // Works

 secret = enc.Encode(Encoding.ASCII.GetBytes(Guid.NewGuid().ToString())); // Fails

 newAuthUrl = string.Format("otpauth://totp/myapp_user?secret={0}", secret);

У меня есть две безумные теории о том, почему это могло бы сработать:

  1. Порт ios требует более 128 бит. Моего комментария / семени достаточно, чтобы превзойти этот предел, что бы это ни случилось... за исключением того, что я фактически дал ему более 128 бит, так как это была строка-указатель.

  2. После декодирования Base32 приложение ios распознает секретную строку как guid и делает с ней что-то еще.

Я ненавижу исправлять ошибки и не знаю, почему исправление сработало. Кто-нибудь может объяснить это? Дополнительные теории заговора по этой теме также приветствуются.

5 ответов

Решение

У меня была та же проблема, что и выше. Оказывается, что Google Authenticator не любит = знаки в приложении IPhone, но не жалуется в Android.

В моем случае я увеличил длину строки до кодирования до base32 с 8 до 10 символов. Это удалило три === в конце строки. Я нашел это в Интернете относительно того, почему знаки = появляются в строках в кодировке base32:

Символ pad (=) не имеет двоичного представления в BASE32; он вставляется в текст BASE32 в качестве заполнителя для сохранения 40-битного выравнивания

В вашем случае выше то же самое произошло, когда вы добавили соль. Второй секрет, который вы вставили, не имеет = в конце.

Надеюсь, это поможет.

5 лет спустя... Мы можем заставить Google Authenticator принимать секретные ключи длиной 16 цифр. Более короткие и длинные ключи просто не работают с сообщением "Недействительный штрих-код. Штрих-код... не является допустимым штрих-кодом токена аутентификации". Потрачено много времени на устранение неполадок, надеюсь, это поможет.

Важна не только длина ключа

Вот как должен выглядеть пример URI: otpauth://totp/Example:alice@google.com? Secret=JBSWY3DPEHPK3PXP&isser=Example

В вашем случае в URI нет "эмитента" или "имени учетной записи", оба рекомендуются.

PS. только для вашего сведения, Google Authenticatior также не поддерживает очень длинные ключи.

У меня тоже с этим проблема.

Эта ссылка действительна

otpauth://totp/xxx.yyy:usertest009%40xxx.yyy?secret=CC5FCZNWTKNTOVN6&period=30&digits=6&algorithm=SHA1&issuer=xxx.yyy

Но с секретным ключом diff он станет недействительным

otpauth://totp/xxx.yyy:usertest009%40xxx.yyy?secret=PBUPKS3SLJAP9V2T&period=30&digits=6&algorithm=SHA1&issuer=xxx.yyy

Я обнаружил проблемы. Секретный ключ должен быть строкой base32. Я использую NodeJS, поэтому использую speakeasy для создания секретной строки base32. Теперь это работает.

Что касается приведенного выше ответа, я не мог понять, как заставить работу base32 у меня (я делаю это только на PHP). У меня были коды, которые работали, и коды, которые не работали, и они выглядели так же случайно.

Я генерировал секрет, основанный на первых 16 символах повышенного значения md5. Иногда они работали, но в большинстве случаев нет.

После очень долгого тестирования я понял, что любая строка с 0 или 1 в строке выйдет из строя. Все остальные вроде в порядке. Возможно, я ошибаюсь (и не стесняйтесь проверять свою гипотезу), но у меня это работает.

$ secret ['1'] = 'XVQ2UIGO75XRUKJO'; //работает

$ secret ['1'] = 'XVQ4UIG07SXRUKJO'; // терпит неудачу

$ secret ['1'] = 'XVQ2UIG07SXRUKJO'; // терпит неудачу

$ secret ['1'] = 'XVQ2UIG07SXRUKJO'; // терпит неудачу

$ secret ['1'] = 'ABCDEFGHIJKLMNOR'; //работает

$ secret ['1'] = '1234567890123456'; // терпит неудачу

$ secret ['1'] = '1A3B5C7D9E1F3G5H'; // терпит неудачу

$ secret ['1'] = 'AB1DE2GH3JK4MN5R'; // терпит неудачу

$ secret ['1'] = 'ABC1EFG2IJK3MNO4'; // терпит неудачу

$ secret ['1'] = 'ABCDEFG2IJK3MNO4'; //работает

$ secret ['1'] = 'ABCD123456789012'; // терпит неудачу

$ secret ['1'] = 'ABCDE23456789012'; // терпит неудачу

$ secret ['1'] = 'ABCDEF3456789012'; // терпит неудачу

$ secret ['1'] = 'ABCDEFG456789012'; // терпит неудачу

$ secret ['1'] = 'ABCDEFGH56789012'; // терпит неудачу

$ secret ['1'] = 'ABCDEFGHIJBKCLMD'; //работает

$ secret ['1'] = 'AAAAAAAAAAAAAAAA'; //работает

$ secret ['1'] = '1111111111111111'; // терпит неудачу

$ secret ['1'] = 'A1A1A1A1A1A1A1A1'; // терпит неудачу

$ secret ['1'] = 'AAA1AAA1AAA1AAAA'; // терпит неудачу

$ secret ['1'] = 'AAAAAAA1AAAAAAAA'; // терпит неудачу

$ secret ['1'] = 'AAAA1AAAAAAAAAAA'; // терпит неудачу

$ secret ['1'] = 'AAA1AAAAAAAAAAAA'; // терпит неудачу

$ secret ['1'] = 'AAAAAAAAAAAAAAAA'; //еще работает

$ secret ['1'] = 'AAAAAAA5AAAAAAAA'; //работает

$ secret ['1'] = 'AAAAAAA1AAAAAAAA'; // терпит неудачу

$ secret ['1'] = 'A5A5A5A5A5A5A5A5'; //работает

$ secret ['1'] = 'A2A2A2A2A2A2A2A2'; //работает

$ secret ['1'] = 'A0A2A2A2A2A2A2A2'; // терпит неудачу

$ secret ['1'] = 'A3A2A2A2A2A2A2A2'; // работает гипотеза, любой 1 или 0 вызовет ошибку

$ secret ['1'] = 'XVQ2UIG17SXRUKJO'; // терпит неудачу с 1

$ secret ['1'] = 'XVQ2UIG27SXRUKJO'; // работает без 1

$ secret ['1'] = 'XVQ2UIG07SXRUKJO'; // сбой с 0

$ secret ['1'] = 'XVQ2UIG37SXRUKJO'; // работает с 3

$ secret ['1'] = 'XV02UIG37SXRUKJO'; // ошибка добавлена ​​0

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