Код-ревью Senior Безопасность мобильных приложений обновлено

Код-ревью: хранение сессии и вход (Swift)

Вопрос

Найдите проблемы безопасности в коде входа.

enum Secrets {
    static let paymentApiKey = "sk_live_51H8xQ2"
}

final class AuthService {
    func login(email: String, password: String) async throws {
        let session = try await api.login(email: email, password: password)
        UserDefaults.standard.set(session.refreshToken, forKey: "refresh")
        UserDefaults.standard.set(password, forKey: "password")
        print("Logged in: \(email), token: \(session.accessToken)")
    }

    func unlockWithFaceID() async -> Bool {
        let ok = (try? await LAContext().evaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, localizedReason: "Вход")) ?? false
        if ok { isLoggedIn = true }
        return ok
    }
}

Коротко

Исправленная схема: ключи платёжного провайдера только на сервере, клиент получает от своего бэкенда одноразовый токен платежа.

Что должен найти ревьюер

  1. Безопасностьстрока 2
    Секретный ключ платёжного API в бинарнике: его извлекут за минуты. Операции с ключом должен выполнять сервер.
  2. Безопасностьстрока 8
    Refresh-токен в UserDefaults хранится открытым текстом. Нужен Keychain.
  3. Безопасностьстрока 9
    Пароль пользователя сохраняется на устройстве. Пароль не хранят вообще.
  4. Безопасностьстрока 10
    Email и access-токен в логах: попадут в системный журнал и крэш-репорты.
  5. Безопасностьстрока 15
    Биометрия только возвращает true, и флаг ставится в коде: проверка обходится хуком. Биометрия должна открывать секрет из Keychain с SecAccessControl.

Разбор

Исправленная схема: ключи платёжного провайдера только на сервере, клиент получает от своего бэкенда одноразовый токен платежа. Refresh-токен в Keychain с доступностью AfterFirstUnlockThisDeviceOnly, а для входа по биометрии отдельная копия с SecAccessControl(.biometryCurrentSet): успешная биометрия буквально отдаёт токен. Пароль не сохраняется, логи без персональных данных.

Ответьте сами, а не прочитайте

В тренажёре вопрос попадёт в повторения и вернётся, когда начнёт забываться. Плюс билеты с зачётом: 20 вопросов, не больше 2 ошибок.