Розробка системи восстановлення пароля в мобільному приложенні
Восстановлення пароля — один з найбільш уязвимих flow з точки зору безпеки. При цьому реалізується часто небережно: "відправили email — дальше не наша зона відповідальності". Насправді мобільна частина несе відповідальність за кілька критичних моментів.
Уязвимості, які частіше всього пропускають
User enumeration. Форма "Введіть email" не повинна повідомляти, зареєстрований ли цей адрес. Повідомлення "Якщо email зареєстрований, ми відправимо лист" — стандартна практика. Повідомлення "Такого користувача не існує" — розкриття інформації про акаунти. Деякі проекти вважають це незначним — але в контексті GDPR це потенційно проблема.
Rate limiting на клієнті. Кнопка "Відправити повторно" повинна бути заблокована на 60–120 секунд після натиснення. Без цього користувач (або скрипт) може spam-бомбардирувати чужий email листами восстановлення. Rate limiting потрібен і на сервері, але клієнт не повинен полегшувати атаку.
Deep link security. Посилання восстановлення вида myapp://reset-password?token=xyz — надо обробити коректно. На Android, якщо не налаштовані App Links з Digital Asset Links, будь-яке приложення може перехопити custom scheme. Використовуємо HTTPS Universal Links (iOS) та HTTPS App Links (Android).
Основний flow
- Користувач вводить email → кнопка "Восстановити" (деактивирована до валідного email).
- Запит на сервер → показуємо "Перевірте почту" незалежно від результату (не має user enumeration).
- У листі — посилання з одноразовим токеном та
expires_in(зазвичай 15–60 хвилин). - Користувач тапає посилання → приложення відкривається через Universal/App Link.
- Токен з URL → екран "Новий пароль".
- Користувач вводить пароль двічі (або один раз з кнопкою "показати").
- PATCH/POST на сервер з токеном + новим паролем.
- Успіх → автоматичний вхід (отримуємо access/refresh tokens) → головний екран.
Обробка deep link в приложенні
Якщо приложення не встановлено — посилання повинно відкрити web-версію (App Clip або просто веб-форма). Це налаштовується через Associated Domains + apple-app-site-association (iOS) та App Links + assetlinks.json (Android).
У SwiftUI + AppCoordinator:
// SceneDelegate або App з @main
.onOpenURL { url in
guard let token = url.queryParameters["token"] else { return }
coordinator.navigate(to: .resetPassword(token: token))
}
Токен передаємо в ViewModel Reset-екрану, не тримаємо його в URL або nav stack довше необхідного.
Екран нового пароля
SecureField з кнопкою "показати/сховати" — стандарт. textContentType(.newPassword) на iOS пропонуватиме генератор паролів Keychain. Це корисно — краще нехай користувач візьме сгенерований пароль, ніж поставить "qwerty123".
Індикатор надійності пароля — кольорова полоса з розрахунком у реальному часі. Використовуємо zxcvbn (є Swift та Kotlin ports) — більш чесна оцінка, ніж "є цифра + буква + символ".
Після успішної зміни — інвалідуємо всі активні сесії (це серверна задача, але мобільне приложення повинно прийняти нові токени та видалити старі з Keychain).
SMS-recovery як альтернатива
OTP на телефон замість email-посилання. Плюси: не треба чекати листа, не залежить від спам-фільтрів. Мінуси: SIM swap атака — зловмисник переоформляє номер та перехоплює OTP. Для high-sensitivity приложень SMS recovery без додаткового фактора недостатня.
Терміни
Повний flow восстановлення пароля (email-форма, deep link handling, екран нового пароля, автологін) — 4–7 робочих днів на одну платформу. Налаштування Universal/App Links + Apple App Site Association, якщо ще не зроблені — плюс 1–2 дні.







