Как правильно хранить пароль в iOS Keychain?

Ответ

Правильный подход: Использовать класс kSecClassGenericPassword с обязательными атрибутами для идентификации записи и настройками защиты.

Ключевые шаги и best practices:

  1. Используйте правильный класс: kSecClassGenericPassword предназначен для паролей и токенов.
  2. Задавайте уникальные идентификаторы: Комбинация kSecAttrAccount и kSecAttrService однозначно идентифицирует запись.
  3. Контролируйте доступ: Атрибут kSecAttrAccessible определяет, когда доступны данные (например, только после разблокировки устройства).
  4. Храните данные как Data: Конвертируйте строки в Data перед сохранением.

Пример сохранения пароля:

import Security

func savePassword(_ password: String, for account: String, service: String = "com.yourapp") -> Bool {

    guard let passwordData = password.data(using: .utf8) else { return false }

    let query: [String: Any] = [
        kSecClass as String: kSecClassGenericPassword,
        kSecAttrAccount as String: account,
        kSecAttrService as String: service,
        kSecAttrAccessible as String: kSecAttrAccessibleWhenUnlockedThisDeviceOnly, // Высокий уровень защиты
        kSecValueData as String: passwordData
    ]

    // Сначала удаляем старую запись, если она есть
    SecItemDelete(query as CFDictionary)

    // Добавляем новую
    let status = SecItemAdd(query as CFDictionary, nil)
    return status == errSecSuccess
}

Рекомендации по безопасности:

  • kSecAttrAccessibleWhenUnlockedThisDeviceOnly — оптимальный выбор: данные доступны только после разблокировки и не синхронизируются с iCloud.
  • Не используйте kSecAttrAccessibleAlways — это небезопасно.
  • Проверяйте коды возврата (errSecSuccess, errSecItemNotFound) для обработки ошибок.
  • Для обновления используйте SecItemUpdate, для удаления — SecItemDelete с аналогичным query.

Ответ 18+ 🔞

Да ты посмотри, что люди творят с этой Keychain, просто пиздец! Сидят, блядь, как мартышки, пытаются впендюрить туда что попало, а потом орут: «Ой, у меня токены утекли, блядь!». Так, слушай сюда, я тебе сейчас разжую, как это делать по-человечьи.

Нормальный, не распиздяйский подход: Юзай класс kSecClassGenericPassword и не забудь про обязательные атрибуты, чтобы потом самому не ебаться с поиском своей же записи.

Основные моменты, чтобы не облажаться:

  1. Класс, ёпта, правильный бери! kSecClassGenericPassword — он как раз для паролей, токенов и прочей чувствительной хуйни. Не надо пытаться туда фотку кота пихать.
  2. Уникально помечай! Связка kSecAttrAccount (логин) и kSecAttrService (название твоего приложения) — это твой гарант, что ты не перепутаешь пароль от банка с паролем от «Одноклассников».
  3. Контролируй доступ, а то проебёшься! Атрибут kSecAttrAccessible — это твой главный охранник. Он решает, когда данные можно достать. Например, только после разблокировки телефона.
  4. Данные — только в Data! Строку свою любимую перед сохранением конвертируй в Data, иначе Security Framework тебя просто пошлёт нахуй.

Вот, смотри, как сохранить пароль без кринжа:

import Security

func savePassword(_ password: String, for account: String, service: String = "com.yourapp") -> Bool {

    // Сначала строку в Data, ебанашка!
    guard let passwordData = password.data(using: .utf8) else { return false }

    // Вот наш волшебный запрос, собираем, как пазл
    let query: [String: Any] = [
        kSecClass as String: kSecClassGenericPassword,
        kSecAttrAccount as String: account,
        kSecAttrService as String: service,
        kSecAttrAccessible as String: kSecAttrAccessibleWhenUnlockedThisDeviceOnly, // Жёсткий режим, синхронизации с iCloud нет
        kSecValueData as String: passwordData
    ]

    // Старую запись нахуй удаляем, чтобы не было конфликтов
    SecItemDelete(query as CFDictionary)

    // И втыкаем новую, свеженькую
    let status = SecItemAdd(query as CFDictionary, nil)
    return status == errSecSuccess // Вернёт true, если всё заебись
}

Теперь про безопасность, чтобы не просрать данные пользователей:

  • kSecAttrAccessibleWhenUnlockedThisDeviceOnly — это наш выбор, блядь! Данные только после разблокировки и только на этом устройстве. Никаких iCloud, никаких бэкапов в iTunes.
  • Забудь как страшный сон про kSecAttrAccessibleAlways — это дыра размером с твою жопу, данные будут доступны всегда, даже если телефон в кармане у вора.
  • Проверяй статусы, ёпта! errSecSuccess — ок, errSecItemNotFound — не нашли, обрабатывай это, не игнорируй.
  • Хочешь обновить? SecItemUpdate. Удалить? SecItemDelete. Всё просто, не выёбывайся.