Двофакторна аутентифікація (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 плохо считався та користувач заблокується відразу після налаштування.
Резервні коди
Без резервних кодів 2FA в крипто-додатку — ризик безповоротної втрати доступу. Генеруємо 8–10 одноразових кодів при активації 2FA. Backend зберігає їх як bcrypt-хеші. Мобільний показує їх один раз з можливістю скопіювати або скачати як текстовий файл.
Реалізація резервних кодів вимагає окремої гілки у flow логіну: поле введення TOTP — дати можливість переключитися на "Використовувати резервний код". Після використання — код інвалідується, користувач отримує попередження про залишок.
Захист самого екрану 2FA
У крипто-додатках критично: екран введення TOTP не повинен знімати скриншоти. На Android:
window.addFlags(WindowManager.LayoutParams.FLAG_SECURE)
На iOS UIScreen не запобігає скриншоту напряму, але можна сховати вміст на applicationWillResignActive. Для поля введення кода — isSecureTextEntry = true, щоб текст не світив у автозаповненні.
Інтеграція TOTP 2FA (налаштування, flow входу, резервні коди, захист екрану) — 1–2 тижні. Вартість розраховується індивідуально.







