[Информационная безопасность, Разработка под iOS, Swift] Keychain API в iOS
Автор
Сообщение
news_bot ®
Стаж: 6 лет 9 месяцев
Сообщений: 27286
Всем привет!
Не так давно столкнулся с необходимостью использования Keychain-а для обеспечения дополнительной защиты при входе в приложение.
Я нашел много хороших статей по этой теме, но в основном там описываются сторонние фреймворки, упрощающие жизнь, а было интересно посмотреть, как работать с API напрямую. В этой статье я попытался объединить документацию Apple с практикой на простом примере.
Начнем с небольших определений
Keychain — зашифрованная база данных, куда сохраняются небольшие объемы пользовательской информации (см. документацию Apple).
Общая схема работы продемонстрирована на рисунке.
Keychain API Services в свои очередь являются часть фреймворка Security, но его рассмотрение требует отдельной статьи.
Добавление элемента
let keychainItemQuery = [
kSecValueData: pass.data(using: .utf8)!,
kSecClass: kSecClassGenericPassword
] as CFDictionary
let status = SecItemAdd(keychainItemQuery, nil)
print("Operation finished with status: \(status)")
Выше приведен пример сохранения пароля в Keychain.
Рассмотрим функцию SecItemAdd подробнее.
func SecItemAdd(_ attributes: CFDictionary,
_ result: UnsafeMutablePointer<CFTypeRef?>?) -> OSStatus
На вход подается объект класса CFDictionary, который в свою очередь является ссылкой на неизменяемый объект словаря.
Что в это словарь входит? На самом деле его состав зависит от решаемой задачи — здесь же мы просто сохраняем простой пароль, давайте разберем этот простейший запрос.
Итак, kSecClass — этот ключ используется для значений хранимых элементов, список их можно посмотреть тут, мы же выбрали стандартный пароль.
kSecValueData — ключ, использующийся для передачи данных элемента.
На этом обязательные ключи заканчиваются, далее идут опциональные. Список таких параметров доступен в документации.
Возвращаемое значение типа OSStatus определяет результат операции сохранения/изменения/удаления, у него так же есть масса значений.
Получение элемента
Для получения элемента из Keychain-а используется метод SecItemCopyMatching.
Формируем запрос в виде словаря, где содержится искомый пароль.
let keychainItem = [
kSecValueData: pass.data(using: .utf8)!,
kSecClass: kSecClassGenericPassword,
kSecReturnAttributes: true,
kSecReturnData: true
] as CFDictionary
var ref: AnyObject?
let status = SecItemCopyMatching(keychainItem, &ref)
if let result = ref as? NSDictionary, let passwordData = result[kSecValueData] as? Data {
print("Operation finished with status: \(status)")
print(result)
let str = String(decoding: passwordData, as: UTF8.self)
print(str)
}
Посмотрим логи:
Operation finished with status: 0
{
accc = "<SecAccessControlRef: ak>";
acct = "";
agrp = "xxx.com.maximenko.xxx";
cdat = "2020-11-19 20:39:43 +0000";
mdat = "2020-11-19 20:39:43 +0000";
musr = {length = 0, bytes = 0x};
pdmn = ak;
persistref = {length = 0, bytes = 0x};
sha1 = {length = 20, bytes = 0xxxxxxxxxxxxxxxxxxxxxxx};
svce = "";
sync = 0;
tomb = 0;
"v_Data" = {length = 3, bytes = 0x4b656b};
}
Kek
Как мы видим, возвращен 0, символизирующий успешный результат поиска и выведен весь список атрибутов, полученных из API (Access group параметр затерт на всякий случай:)). Эти атрибуты подробно описаны тут.
Значение по ключу kSecValueData нас собственно тут интересует, успешно разворачиваем его в строку, далее выведенную терминал.
Обновление элемента
Для этого есть метод SecItemUpdate.
На вход подается 2 CFDictionary словаря — в первом информация об обновляемом элементе, во втором — та информация, на которую надо будет заменить старую.
let query = [
kSecClass: kSecClassGenericPassword,
] as CFDictionary
let updateFields = [
kSecValueData: pass.data(using: .utf8)!
] as CFDictionary
let status = SecItemUpdate(query, updateFields)
На примере простого пароля — в первом запросе указываем что именно требуется найти для замены, во втором — то ключ-значение, которое мы обновим в найденном элементе.
Удаление элемента
Для удаления используем SecItemDelete.
У него на входе один параметр — словарь c информацией об удаляемом элементе, который надо найти.
Возвращает статус выполнения операции типа OSStatus.
let query = [
kSecClass: kSecClassGenericPassword,
kSecValueData: pass.data(using: .utf8)!
] as CFDictionary
let res = SecItemDelete(query)
Подведение итогов
В данной статье рассматривается работа с Keychain-ом на примере нескольких основных методов. Если увидите какие-то неточности, ошибки или просто хотите более подробно обсудить тему, пишите в комментарии или Telegram (skipperprivate).
P.S.
Если будет интересно, можно отдельную статью посвятить работе с более сложными сущностями вроде Интернет-пароля, с большим количеством полей и т.д., или обсудить подобное в комментариях.
===========
Источник:
habr.com
===========
Похожие новости:
- [Информационная безопасность] Спецификация классификации методологии безопасной разработки
- [Safari, Облачные сервисы, Игры и игровые приставки] GeForce Now официально заработал на iOS
- [Информационная безопасность] Страх перед автоматизацией работы и другие тренды в мировой и российской кибербезопасности
- [Информационная безопасность, Разработка веб-сайтов, Облачные сервисы] Вебинар DataLine «Защита веб-приложений: как это нужно делать сегодня» 26 ноября
- [Информационная безопасность, Исследования и прогнозы в IT] NordPass опубликовала рейтинг самых слабых паролей из утечек этого года
- [Информационная безопасность] ProtonVPN препятствует приложениям из списка исключений Big Sur обходить брандмауэр
- [Гаджеты, IT-компании] Apple выплатит $113 миллионов властям США из-за замедления старых iPhone
- [Информационная безопасность, IT-инфраструктура, Удалённая работа] Виртуализация USB устройств в сетях
- [Информационная безопасность, Софт] Обзор решений SIEM (Security information and event management)
- [Информационная безопасность, Компьютерное железо, IT-компании] Microsoft при поддержке Intel, AMD и Qualcomm представила стандарт чипа безопасности Pluton
Теги для поиска: #_informatsionnaja_bezopasnost (Информационная безопасность), #_razrabotka_pod_ios (Разработка под iOS), #_swift, #_ios, #_ios_sdk, #_ios_razrabotka (ios разработка), #_ios_development, #_keychain, #_swift, #_xcode, #_informatsionnaja_bezopasnost (
Информационная безопасность
), #_razrabotka_pod_ios (
Разработка под iOS
), #_swift
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 23-Ноя 00:21
Часовой пояс: UTC + 5
Автор | Сообщение |
---|---|
news_bot ®
Стаж: 6 лет 9 месяцев |
|
Всем привет! Не так давно столкнулся с необходимостью использования Keychain-а для обеспечения дополнительной защиты при входе в приложение. Я нашел много хороших статей по этой теме, но в основном там описываются сторонние фреймворки, упрощающие жизнь, а было интересно посмотреть, как работать с API напрямую. В этой статье я попытался объединить документацию Apple с практикой на простом примере. Начнем с небольших определений Keychain — зашифрованная база данных, куда сохраняются небольшие объемы пользовательской информации (см. документацию Apple). Общая схема работы продемонстрирована на рисунке. Keychain API Services в свои очередь являются часть фреймворка Security, но его рассмотрение требует отдельной статьи. Добавление элемента let keychainItemQuery = [
kSecValueData: pass.data(using: .utf8)!, kSecClass: kSecClassGenericPassword ] as CFDictionary let status = SecItemAdd(keychainItemQuery, nil) print("Operation finished with status: \(status)") Выше приведен пример сохранения пароля в Keychain. Рассмотрим функцию SecItemAdd подробнее. func SecItemAdd(_ attributes: CFDictionary,
_ result: UnsafeMutablePointer<CFTypeRef?>?) -> OSStatus На вход подается объект класса CFDictionary, который в свою очередь является ссылкой на неизменяемый объект словаря. Что в это словарь входит? На самом деле его состав зависит от решаемой задачи — здесь же мы просто сохраняем простой пароль, давайте разберем этот простейший запрос. Итак, kSecClass — этот ключ используется для значений хранимых элементов, список их можно посмотреть тут, мы же выбрали стандартный пароль. kSecValueData — ключ, использующийся для передачи данных элемента. На этом обязательные ключи заканчиваются, далее идут опциональные. Список таких параметров доступен в документации. Возвращаемое значение типа OSStatus определяет результат операции сохранения/изменения/удаления, у него так же есть масса значений. Получение элемента Для получения элемента из Keychain-а используется метод SecItemCopyMatching. Формируем запрос в виде словаря, где содержится искомый пароль. let keychainItem = [
kSecValueData: pass.data(using: .utf8)!, kSecClass: kSecClassGenericPassword, kSecReturnAttributes: true, kSecReturnData: true ] as CFDictionary var ref: AnyObject? let status = SecItemCopyMatching(keychainItem, &ref) if let result = ref as? NSDictionary, let passwordData = result[kSecValueData] as? Data { print("Operation finished with status: \(status)") print(result) let str = String(decoding: passwordData, as: UTF8.self) print(str) } Посмотрим логи: Operation finished with status: 0 { accc = "<SecAccessControlRef: ak>"; acct = ""; agrp = "xxx.com.maximenko.xxx"; cdat = "2020-11-19 20:39:43 +0000"; mdat = "2020-11-19 20:39:43 +0000"; musr = {length = 0, bytes = 0x}; pdmn = ak; persistref = {length = 0, bytes = 0x}; sha1 = {length = 20, bytes = 0xxxxxxxxxxxxxxxxxxxxxxx}; svce = ""; sync = 0; tomb = 0; "v_Data" = {length = 3, bytes = 0x4b656b}; } Kek Как мы видим, возвращен 0, символизирующий успешный результат поиска и выведен весь список атрибутов, полученных из API (Access group параметр затерт на всякий случай:)). Эти атрибуты подробно описаны тут. Значение по ключу kSecValueData нас собственно тут интересует, успешно разворачиваем его в строку, далее выведенную терминал. Обновление элемента Для этого есть метод SecItemUpdate. На вход подается 2 CFDictionary словаря — в первом информация об обновляемом элементе, во втором — та информация, на которую надо будет заменить старую. let query = [
kSecClass: kSecClassGenericPassword, ] as CFDictionary let updateFields = [ kSecValueData: pass.data(using: .utf8)! ] as CFDictionary let status = SecItemUpdate(query, updateFields) На примере простого пароля — в первом запросе указываем что именно требуется найти для замены, во втором — то ключ-значение, которое мы обновим в найденном элементе. Удаление элемента Для удаления используем SecItemDelete. У него на входе один параметр — словарь c информацией об удаляемом элементе, который надо найти. Возвращает статус выполнения операции типа OSStatus. let query = [
kSecClass: kSecClassGenericPassword, kSecValueData: pass.data(using: .utf8)! ] as CFDictionary let res = SecItemDelete(query) Подведение итогов В данной статье рассматривается работа с Keychain-ом на примере нескольких основных методов. Если увидите какие-то неточности, ошибки или просто хотите более подробно обсудить тему, пишите в комментарии или Telegram (skipperprivate). P.S. Если будет интересно, можно отдельную статью посвятить работе с более сложными сущностями вроде Интернет-пароля, с большим количеством полей и т.д., или обсудить подобное в комментариях. =========== Источник: habr.com =========== Похожие новости:
Информационная безопасность ), #_razrabotka_pod_ios ( Разработка под iOS ), #_swift |
|
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 23-Ноя 00:21
Часовой пояс: UTC + 5