Реалізація графічного ключа для входу в мобільне приложення
Графічний ключ — паттерн з Android, у iOS зустрічається рідше (немає системного аналога). Принцип той же, що й у PIN: локальна розблокування сховища без відправки секрету на сервер. Але у паттерна є специфічні проблеми безпеки, які надо розуміти перед початком реалізації.
Проблема жирних слідів
На екрані телефону залишаються сліди від пальця. Паттерн з 9 точок відновлюється візуально з відстані 1–2 метра під правильним освітленням. Дослідження Авраама та колег (2010) показало: більшість користувачів рисують L-, Z- або S-образні паттерни — 12 найбільш популярних паттернів покривають ~20% користувацької бази. Це важливий контекст для клієнта при виборі методу аутентифікації.
Кодування паттерна
Стандартна сітка 3×3 — 9 точок з індексами 0–8. Паттерн — послідовність індексів. Мінімальна довжина — 4 точки (вимога Android). З 9 точок з мінімальною довжиною 4 можливих паттернів ~389 112 — істотно менше, ніж 6-значний PIN (1 000 000 комбінацій).
Кодуємо паттерн у рядок індексів: [0,1,2,5,8] → "01258". Цей рядок використовуємо як input для деривації ключа — та сама схема PBKDF2, що й для PIN. Паттерн у plaintext ніколи не зберігаємо.
Кастомна реалізація View
На Android можна взяти com.github.itsxtt:pattern-lock або аналогічні open-source бібліотеки — базову логіку рисування ліній. Але в enterprise-проектах пишемо самі: повний контроль над візуалом, криптографічною частиною, та немає залежності від непідтримуваної бібліотеки.
Jetpack Compose:
@Composable
fun PatternLockView(
onPatternComplete: (List<Int>) -> Unit
) {
val selectedDots = remember { mutableStateListOf<Int>() }
var currentPosition by remember { mutableStateOf(Offset.Zero) }
Canvas(
modifier = Modifier
.fillMaxSize()
.pointerInput(Unit) {
detectDragGestures(
onDragStart = { offset -> /* знайти найближчу точку */ },
onDrag = { change, _ ->
currentPosition = change.position
// добавити точку якщо касання в радіусі
},
onDragEnd = {
if (selectedDots.size >= 4) onPatternComplete(selectedDots.toList())
selectedDots.clear()
}
)
}
) {
// рисуємо точки та лінії між selectedDots + лінію до currentPosition
}
}
Ключові деталі: точку можна відвідати тільки один раз; лінія, що перетинає незачеплену точку, автоматично її додає (стандартне поведінка Android Pattern Lock); мінімальна відстань касання до точки — ~24dp.
Приховуємо паттерн через 500–800мс після завершення введення — лінії зникають, точки залишаються. Це запобігає shoulder surfing.
iOS: кастомна реалізація
У iOS немає системного Pattern Lock. Реалізуємо через SwiftUI Canvas + DragGesture. Логіка аналогічна, візуал адаптуємо під iOS Human Interface Guidelines. На iOS паттерн зустрічається рідше — зазвичай це специфічний запит клієнта (наприклад, дитячі приложення або спеціалізовані enterprise-інструменти).
Fallback та лічильник помилок
Після 5 невдалих спроб — вимагаємо повний логін через credentials. Лічильник у Keychain (iOS) або EncryptedSharedPreferences (Android). Після успішного логіну скидаємо лічильник та пропонуємо перерисувати паттерн — важливо попередити користувача, що старий паттерн скинутий.
Коли не варто використовувати
Паттерн — слабший за PIN при рівній кількості символів. Для банківських приложень, медичних даних або корпоративного доступу — рекомендуємо PIN 6+ цифр з PBKDF2 або біометрію. Паттерн уместен у приложеннях, де зручність важлива за максимальну безпеку: трекери, органайзери, приложення для дітей.
Терміни
Кастомна реалізація PatternLock з правильною криптографічною схемою на одній платформі — 5–8 робочих днів. На обох платформах — 10–14 днів (з адаптацією UX під кожну ОС).







