Реализация двухфакторной аутентификации (TOTP) для мобильного криптоприложения
TOTP (Time-based One-Time Password, RFC 6238) — стандарт, который реализует Google Authenticator, Authy и большинство корпоративных 2FA-приложений. Для крипто-приложения это обязательный минимум: SMS-коды перехватываются через SIM-swap, TOTP — нет.
Как работает TOTP
Алгоритм: HMAC-SHA1 от текущего времени (окно 30 секунд) и shared secret. Shared secret генерируется при настройке 2FA и хранится и на сервере, и у пользователя (в authenticator-приложении). Никакой сетевой передачи при каждой аутентификации — только проверка вычисленного кода.
На backend верификация через популярные библиотеки: pyotp (Python), otplib (Node.js), google-authenticator (Java). На мобильном клиенте код вводится вручную из authenticator-приложения — никакой дополнительной логики TOTP не нужно.
Встраивание 2FA в процесс входа
Классический flow: логин/пароль → проверка на backend → если у пользователя активна 2FA, backend возвращает промежуточный токен → мобильный показывает экран ввода TOTP → backend верифицирует код и выдаёт полноценный JWT.
sealed class LoginState {
object Idle : LoginState()
object Loading : LoginState()
data class TwoFactorRequired(val tempToken: String) : LoginState()
data class Success(val authToken: String) : LoginState()
data class Error(val message: String) : LoginState()
}
class LoginViewModel(private val authRepository: AuthRepository) : ViewModel() {
val state = MutableStateFlow<LoginState>(LoginState.Idle)
fun submitTOTP(code: String, tempToken: String) {
viewModelScope.launch {
state.value = LoginState.Loading
authRepository.verifyTOTP(code, tempToken)
.onSuccess { token -> state.value = LoginState.Success(token) }
.onFailure { e ->
state.value = LoginState.Error(
if (e is InvalidCodeException) "Неверный код" else "Ошибка сервера"
)
}
}
}
}
Настройка 2FA пользователем
Важный шаг — onboarding. Нужно показать QR-код для сканирования в Google Authenticator / Authy, плюс текстовый secret для ручного ввода. QR-код содержит otpauth://-URI:
otpauth://totp/CryptoApp:[email protected]?secret=BASE32SECRET&issuer=CryptoApp&algorithm=SHA1&digits=6&period=30
На Android генерируем QR через библиотеку zxing-android-embedded или qrcode-kotlin. На iOS — CoreImage.CIFilter.qrCodeGenerator.
После сканирования — обязательная верификация: пользователь вводит первый сгенерированный код, backend проверяет до сохранения 2FA. Это отсекает ситуацию, когда QR плохо считался и пользователь заблокировался сразу после настройки.
Backup-коды
Без backup-кодов 2FA в крипто-приложении — риск безвозвратной потери доступа. Генерируем 8-10 одноразовых кодов при активации 2FA. Backend хранит их как bcrypt-хэши. Мобильный показывает их один раз с возможностью скопировать или скачать как текстовый файл.
Реализация backup-кодов требует отдельной ветки в flow логина: если поле ввода TOTP — дать возможность переключиться на "Использовать резервный код". После использования — код инвалидируется, пользователь получает предупреждение о количестве оставшихся.
Защита самого экрана 2FA
В крипто-приложениях критично: экран ввода TOTP не должен снимать скриншоты. На Android:
window.addFlags(WindowManager.LayoutParams.FLAG_SECURE)
На iOS UIScreen не предотвращает скриншот напрямую, но можно скрыть содержимое при отображении switcher через applicationWillResignActive. Для поля ввода кода — isSecureTextEntry = true, чтобы не светился в автозаполнении.
Интеграция TOTP 2FA (настройка, flow входа, backup-коды, защита экрана) — 1-2 недели. Стоимость рассчитывается индивидуально.







