{"id":37307,"date":"2023-06-18T07:15:38","date_gmt":"2023-06-17T22:15:38","guid":{"rendered":"https:\/\/8gfg.shop\/blog\/?p=37307"},"modified":"2023-06-18T07:15:38","modified_gmt":"2023-06-17T22:15:38","slug":"how-to-use-keychain-to-enhance-ios-app-security","status":"publish","type":"post","link":"https:\/\/8gfg.shop\/blog\/development\/how-to-use-keychain-to-enhance-ios-app-security","title":{"rendered":"iOS \uc571 \ubcf4\uc548 \uac15\ud654\ub97c \uc704\ud55c Keychain \uc0ac\uc6a9 \ubc29\ubc95"},"content":{"rendered":"
<\/p>\n
iOS \uac1c\ubc1c\uc790\ub4e4\uc740 \ub2e4\uc591\ud55c \uc815\ubcf4\ub97c \uad00\ub9ac\ud558\ub294 \uc571\uc744 \ub9cc\ub4e4 \ub54c, \uc0ac\uc6a9\uc790 \ub370\uc774\ud130 \ubcf4\ud638\ub97c \uc704\ud55c \ubcf4\uc548 \uac15\ud654\uac00 \ud544\uc218\uc801\uc774\ub77c\uace0 \uc778\uc2dd\ud558\uace0 \uc788\uc2b5\ub2c8\ub2e4. \uc0ac\uc6a9\uc790 \ube44\ubc00\ubc88\ud638, \ub85c\uadf8\uc778 \uc815\ubcf4, \uc778\uc99d\uc11c, \ud1a0\ud070 \ub4f1 \uc911\uc694\ud55c \uc815\ubcf4\ub4e4\uc740 \uc571 \ub0b4\ubd80\uc5d0\uc11c \uc548\uc804\ud558\uac8c \ubcf4\ud638\ub418\uc5b4\uc57c \ud569\ub2c8\ub2e4. \uc774\ub97c \uc704\ud574 iOS\uc5d0\uc11c\ub294 Keychain\uc774\ub77c\ub294 \ubcf4\uc548 \uba54\ucee4\ub2c8\uc998\uc774 \uc81c\uacf5\ub429\ub2c8\ub2e4.<\/p>\n
Keychain\uc740 iOS\uc5d0\uc11c \uae30\ubcf8\uc801\uc73c\ub85c \uc81c\uacf5\ud558\ub294 \uace0\uae09 \ubcf4\uc548 \ud504\ub808\uc784\uc6cc\ud06c\uc785\ub2c8\ub2e4. \uc571\uc5d0\uc11c \uc0ac\uc6a9\uc790 \ub370\uc774\ud130\ub97c \uc548\uc804\ud558\uac8c \uc800\uc7a5\ud558\uace0 \uad00\ub9ac\ud558\ub294 \ubc29\ubc95\uc744 \uc81c\uacf5\ud569\ub2c8\ub2e4. Keychain\uc740 \ubcf4\uc548\uc744 \uc704\ud574 \uc554\ud638\ud654\ub97c \uc0ac\uc6a9\ud558\uba70, iOS\uc5d0\uc11c\ub294 \uc571\ub9c8\ub2e4 \ubcc4\ub3c4\ub85c \ubd84\ub9ac\ub418\uc5b4 \uad00\ub9ac\ub429\ub2c8\ub2e4. \uc774\ub294 \uc571 \ub0b4\ubd80\uc5d0\uc11c \uc548\uc804\ud558\uac8c \ub370\uc774\ud130\ub97c \uacf5\uc720\ud560 \uc218 \uc788\ub3c4\ub85d \ud569\ub2c8\ub2e4.<\/p>\n
\uc774\ubc88 \uae00\uc5d0\uc11c\ub294 Keychain\uc744 \uc774\uc6a9\ud55c iOS \uc571 \ubcf4\uc548 \uac15\ud654 \ubc29\ubc95\uc5d0 \ub300\ud574 \uc54c\uc544\ubcf4\uaca0\uc2b5\ub2c8\ub2e4.<\/p>\n
iOS\uc5d0\uc11c Keychain API\ub294 C \uc5b8\uc5b4\ub85c \uc791\uc131\ub418\uc5b4 \uc788\uc2b5\ub2c8\ub2e4. \uc774\ub97c \uc774\uc6a9\ud574 Objective-C\ub098 Swift\uc5d0\uc11c Keychain\uc744 \uc0ac\uc6a9\ud560 \uc218 \uc788\uc2b5\ub2c8\ub2e4. Keychain API\ub294 \ub2e4\uc74c\uacfc \uac19\uc740 \uae30\ub2a5\uc744 \uc81c\uacf5\ud569\ub2c8\ub2e4.<\/p>\n
\uc774 \uc911\uc5d0\uc11c \ub370\uc774\ud130 \uc800\uc7a5 \ubc0f \uac80\uc0c9, \ub370\uc774\ud130 \uc218\uc815 \ubc0f \uc0ad\uc81c, \uadf8\ub9ac\uace0 \ud0a4 \uc0dd\uc131 \ubc0f \uc0ad\uc81c\uc5d0 \ub300\ud574 \uc0b4\ud3b4\ubcf4\uaca0\uc2b5\ub2c8\ub2e4.<\/p>\n
Keychain\uc5d0\uc11c \ub370\uc774\ud130\ub97c \uc800\uc7a5\ud558\uace0 \uac80\uc0c9\ud558\ub294 \ubc29\ubc95\uc740 \ub450 \uac00\uc9c0\uac00 \uc788\uc2b5\ub2c8\ub2e4. \uccab \ubc88\uc9f8\ub294 Generic Password\ub97c \uc774\uc6a9\ud558\ub294 \uac83\uc774\uace0, \ub450 \ubc88\uc9f8\ub294 Internet Password\ub97c \uc774\uc6a9\ud558\ub294 \uac83\uc785\ub2c8\ub2e4. Generic Password\ub294 \uc0ac\uc6a9\uc790 \uc774\ub984\uacfc \ube44\ubc00\ubc88\ud638\uc640 \uac19\uc740 \uc77c\ubc18\uc801\uc778 \ube44\ubc00\ubc88\ud638\ub97c \uc800\uc7a5\ud558\ub294\ub370 \uc0ac\uc6a9\ub429\ub2c8\ub2e4. Internet Password\ub294 \uc6f9\uc0ac\uc774\ud2b8\ub098 \uc571\uc5d0\uc11c \uc0ac\uc6a9\ud558\ub294 \ube44\ubc00\ubc88\ud638\ub97c \uc800\uc7a5\ud558\ub294\ub370 \uc0ac\uc6a9\ub429\ub2c8\ub2e4.<\/p>\n
\uba3c\uc800 Generic Password\ub97c \uc774\uc6a9\ud574 \ub370\uc774\ud130\ub97c \uc800\uc7a5\ud558\ub294 \ubc29\ubc95\uc744 \uc0b4\ud3b4\ubcf4\uaca0\uc2b5\ub2c8\ub2e4. \ub2e4\uc74c\uc740 Keychain\uc5d0 \ub370\uc774\ud130\ub97c \uc800\uc7a5\ud558\ub294 \uc608\uc81c \ucf54\ub4dc\uc785\ub2c8\ub2e4.<\/p>\n
func save(key: String, data: Data) -> Bool {\n let query: [String: Any] = [\n kSecClass as String: kSecClassGenericPassword,\n kSecAttrAccount as String: key,\n kSecValueData as String: data\n ]\n\n let status = SecItemAdd(query as CFDictionary, nil)\n\n return status == errSecSuccess\n}<\/code><\/pre>\n\uc704 \ucf54\ub4dc\uc5d0\uc11c\ub294 kSecClassGenericPassword\ub97c \uc774\uc6a9\ud574 Generic Password\ub97c \uc124\uc815\ud569\ub2c8\ub2e4. kSecAttrAccount\ub294 \ub370\uc774\ud130\ub97c \uc800\uc7a5\ud560 \ub54c \uc0ac\uc6a9\ud560 \ud0a4\ub97c \uc9c0\uc815\ud569\ub2c8\ub2e4. kSecValueData\ub294 \uc2e4\uc81c \ub370\uc774\ud130\ub97c \uc800\uc7a5\ud569\ub2c8\ub2e4.<\/p>\n
\ub2e4\uc74c\uc740 Generic Password\ub97c \uc774\uc6a9\ud574 \ub370\uc774\ud130\ub97c \uac80\uc0c9\ud558\ub294 \uc608\uc81c \ucf54\ub4dc\uc785\ub2c8\ub2e4.<\/p>\n
func load(key: String) -> Data? {\n let query: [String: Any] = [\n kSecClass as String: kSecClassGenericPassword,\n kSecAttrAccount as String: key,\n kSecMatchLimit as String: kSecMatchLimitOne,\n kSecReturnData as String: true\n ]\n\n var result: AnyObject?\n let status = SecItemCopyMatching(query as CFDictionary, &result)\n\n if status == errSecSuccess {\n return result as? Data\n }\n\n return nil\n}<\/code><\/pre>\n\uc774 \ucf54\ub4dc\uc5d0\uc11c\ub294 kSecClassGenericPassword\ub97c \uc774\uc6a9\ud574 Generic Password\ub97c \uc124\uc815\ud569\ub2c8\ub2e4. kSecAttrAccount\ub294 \uac80\uc0c9\ud560 \ub370\uc774\ud130\uc758 \ud0a4\ub97c \uc9c0\uc815\ud569\ub2c8\ub2e4. kSecMatchLimit\ub294 \uac80\uc0c9 \uacb0\uacfc\uc758 \uac1c\uc218\ub97c \uc9c0\uc815\ud569\ub2c8\ub2e4. kSecReturnData\ub294 \uac80\uc0c9 \uacb0\uacfc\ub85c \ub370\uc774\ud130\ub97c \ubc18\ud658\ud569\ub2c8\ub2e4.<\/p>\n
\ub2e4\uc74c\uc740 Internet Password\ub97c \uc774\uc6a9\ud574 \ub370\uc774\ud130\ub97c \uc800\uc7a5\ud558\ub294 \uc608\uc81c \ucf54\ub4dc\uc785\ub2c8\ub2e4.<\/p>\n
func save(server: String, account: String, password: String) -> Bool {\n let query: [String: Any] = [\n kSecClass as String: kSecClassInternetPassword,\n kSecAttrServer as String: server,\n kSecAttrAccount as String: account,\n kSecValueData as String: password.data(using: .utf8)!\n ]\n\n let status = SecItemAdd(query as CFDictionary, nil)\n\n return status == errSecSuccess\n}<\/code><\/pre>\n\uc704 \ucf54\ub4dc\uc5d0\uc11c\ub294 kSecClassInternetPassword\ub97c \uc774\uc6a9\ud574 Internet Password\ub97c \uc124\uc815\ud569\ub2c8\ub2e4. kSecAttrServer\uc640 kSecAttrAccount\ub294 \ub370\uc774\ud130\ub97c \uc800\uc7a5\ud560 \ub54c \uc0ac\uc6a9\ud560 \uc11c\ubc84 \uc774\ub984\uacfc \uacc4\uc815 \uc774\ub984\uc744 \uc9c0\uc815\ud569\ub2c8\ub2e4. kSecValueData\ub294 \uc2e4\uc81c \ub370\uc774\ud130\ub97c \uc800\uc7a5\ud569\ub2c8\ub2e4.<\/p>\n
\ub2e4\uc74c\uc740 Internet Password\ub97c \uc774\uc6a9\ud574 \ub370\uc774\ud130\ub97c \uac80\uc0c9\ud558\ub294 \uc608\uc81c \ucf54\ub4dc\uc785\ub2c8\ub2e4.<\/p>\n
func load(server: String, account: String) -> String? {\n let query: [String: Any] = [\n kSecClass as String: kSecClassInternetPassword,\n kSecAttrServer as String: server,\n kSecAttrAccount as String: account,\n kSecMatchLimit as String: kSecMatchLimitOne,\n kSecReturnData as String: true\n ]\n\n var result: AnyObject?\n let status = SecItemCopyMatching(query as CFDictionary, &result)\n\n if status == errSecSuccess {\n if let data = result as? Data {\n return String(data: data, encoding: .utf8)\n }\n }\n\n return nil\n}<\/code><\/pre>\n\uc774 \ucf54\ub4dc\uc5d0\uc11c\ub294 kSecClassInternetPassword\ub97c \uc774\uc6a9\ud574 Internet Password\ub97c \uc124\uc815\ud569\ub2c8\ub2e4. kSecAttrServer\uc640 kSecAttrAccount\ub294 \uac80\uc0c9\ud560 \ub370\uc774\ud130\uc758 \uc11c\ubc84 \uc774\ub984\uacfc \uacc4\uc815 \uc774\ub984\uc744 \uc9c0\uc815\ud569\ub2c8\ub2e4. kSecMatchLimit\ub294 \uac80\uc0c9 \uacb0\uacfc\uc758 \uac1c\uc218\ub97c \uc9c0\uc815\ud569\ub2c8\ub2e4. kSecReturnData\ub294 \uac80\uc0c9 \uacb0\uacfc\ub85c \ub370\uc774\ud130\ub97c \ubc18\ud658\ud569\ub2c8\ub2e4.<\/p>\n
\ub370\uc774\ud130 \uc218\uc815 \ubc0f \uc0ad\uc81c<\/h3>\n
Keychain\uc5d0\uc11c \ub370\uc774\ud130\ub97c \uc218\uc815\ud558\uac70\ub098 \uc0ad\uc81c\ud558\ub294 \ubc29\ubc95\uc740 \ub370\uc774\ud130\ub97c \uac80\uc0c9\ud55c \ud6c4, \ud574\ub2f9 \ub370\uc774\ud130\ub97c \uc218\uc815\ud558\uac70\ub098 \uc0ad\uc81c\ud558\ub294 \uac83\uc785\ub2c8\ub2e4. \ub2e4\uc74c\uc740 Generic Password\ub97c \uc774\uc6a9\ud574 \ub370\uc774\ud130\ub97c \uc218\uc815\ud558\ub294 \uc608\uc81c \ucf54\ub4dc\uc785\ub2c8\ub2e4.<\/p>\n
func update(key: String, data: Data) -> Bool {\n let query: [String: Any] = [\n kSecClass as String: kSecClassGenericPassword,\n kSecAttrAccount as String: key\n ]\n\n let attributes: [String: Any] = [\n kSecValueData as String: data\n ]\n\n let status = SecItemUpdate(query as CFDictionary, attributes as CFDictionary)\n\n return status == errSecSuccess\n}<\/code><\/pre>\n\uc774 \ucf54\ub4dc\uc5d0\uc11c\ub294 \uba3c\uc800 \ub370\uc774\ud130\ub97c \uac80\uc0c9\ud55c \ud6c4, kSecValueData\ub97c \uc774\uc6a9\ud574 \ub370\uc774\ud130\ub97c \uc218\uc815\ud569\ub2c8\ub2e4.<\/p>\n
\ub2e4\uc74c\uc740 Generic Password\ub97c \uc774\uc6a9\ud574 \ub370\uc774\ud130\ub97c \uc0ad\uc81c\ud558\ub294 \uc608\uc81c \ucf54\ub4dc\uc785\ub2c8\ub2e4.<\/p>\n
func delete(key: String) -> Bool {\n let query: [String: Any] = [\n kSecClass as String: kSecClassGenericPassword,\n kSecAttrAccount as String: key\n ]\n\n let status = SecItemDelete(query as CFDictionary)\n\n return status == errSecSuccess\n}<\/code><\/pre>\n\uc774 \ucf54\ub4dc\uc5d0\uc11c\ub294 \uba3c\uc800 \ub370\uc774\ud130\ub97c \uac80\uc0c9\ud55c \ud6c4, SecItemDelete\ub97c \uc774\uc6a9\ud574 \ub370\uc774\ud130\ub97c \uc0ad\uc81c\ud569\ub2c8\ub2e4.<\/p>\n
\ud0a4 \uc0dd\uc131 \ubc0f \uc0ad\uc81c<\/h3>\n
Keychain\uc5d0\uc11c\ub294 \ud0a4\ub97c \uc0dd\uc131\ud558\uace0 \uc0ad\uc81c\ud558\ub294 \ubc29\ubc95\ub3c4 \uc81c\uacf5\ud569\ub2c8\ub2e4. \ub2e4\uc74c\uc740 \ud0a4\ub97c \uc0dd\uc131\ud558\ub294 \uc608\uc81c \ucf54\ub4dc\uc785\ub2c8\ub2e4.<\/p>\n
func generateKey() -> String? {\n let query: [String: Any] = [\n kSecClass as String: kSecClassGenericPassword,\n kSecAttrAccessible as String: kSecAttrAccessibleWhenUnlockedThisDeviceOnly,\n kSecAttrLabel as String: \"My Key\"\n ]\n\n var result: AnyObject?\n let status = SecItemAdd(query as CFDictionary, &result)\n\n if status == errSecSuccess, let keyData = result as? Data {\n return String(data: keyData, encoding: .utf8)\n }\n\n return nil\n}<\/code><\/pre>\n\uc704 \ucf54\ub4dc\uc5d0\uc11c\ub294 kSecClassGenericPassword\ub97c \uc774\uc6a9\ud574 \ud0a4\ub97c \uc0dd\uc131\ud569\ub2c8\ub2e4. kSecAttrAccessible\ub294 \ud0a4\ub97c \uc800\uc7a5\ud560 \uc218 \uc788\ub294 \ubcf4\ud638 \ud074\ub798\uc2a4\ub97c \uc9c0\uc815\ud569\ub2c8\ub2e4. kSecAttrLabel\uc740 \ud0a4 \uc774\ub984\uc744 \uc9c0\uc815\ud569\ub2c8\ub2e4.<\/p>\n
\ub2e4\uc74c\uc740 \ud0a4\ub97c \uc0ad\uc81c\ud558\ub294 \uc608\uc81c \ucf54\ub4dc\uc785\ub2c8\ub2e4.<\/p>\n
func deleteKey(key: String) -> Bool {\n let query: [String: Any] = [\n kSecClass as String: kSecClassGenericPassword,\n kSecAttrAccount as String: key\n ]\n\n let status = SecItemDelete(query as CFDictionary)\n\n return status == errSecSuccess\n}<\/code><\/pre>\n\uc704 \ucf54\ub4dc\uc5d0\uc11c\ub294 kSecClassGenericPassword\ub97c \uc774\uc6a9\ud574 \ud0a4\ub97c \uc0ad\uc81c\ud569\ub2c8\ub2e4. kSecAttrAccount\ub294 \uc0ad\uc81c\ud560 \ud0a4\ub97c \uc9c0\uc815\ud569\ub2c8\ub2e4.<\/p>\n
iOS Keychain \uc11c\ube44\uc2a4\uc640 \uc5d1\uc138\uc2a4 \uadf8\ub8f9 \uae30\ub2a5 \ud65c\uc6a9<\/h2>\n
iOS\uc5d0\uc11c\ub294 Keychain \uc11c\ube44\uc2a4\uc640 \uc5d1\uc138\uc2a4 \uadf8\ub8f9 \uae30\ub2a5\uc744 \uc774\uc6a9\ud574 \uc571 \uac04 \ub370\uc774\ud130 \uacf5\uc720\ub97c \ud560 \uc218 \uc788\uc2b5\ub2c8\ub2e4. \uc774\ub97c \uc774\uc6a9\ud574 \uc5ec\ub7ec \uc571\uc5d0\uc11c \uacf5\ud1b5\uc73c\ub85c \uc0ac\uc6a9\ud558\ub294 \ub370\uc774\ud130\ub97c \uad00\ub9ac\ud560 \uc218 \uc788\uc2b5\ub2c8\ub2e4.<\/p>\n
\uba3c\uc800 Keychain \uc11c\ube44\uc2a4\ub97c \uc774\uc6a9\ud558\ub294 \ubc29\ubc95\uc5d0 \ub300\ud574 \uc54c\uc544\ubcf4\uaca0\uc2b5\ub2c8\ub2e4. Keychain \uc11c\ube44\uc2a4\ub294 \ub3d9\uc77c\ud55c \uc571 \ub0b4\uc5d0\uc11c \uacf5\uc720\ub418\ub294 \ub370\uc774\ud130\ub97c \uad00\ub9ac\ud558\ub294 \ub370 \uc0ac\uc6a9\ub429\ub2c8\ub2e4. \ub2e4\uc74c\uc740 Keychain \uc11c\ube44\uc2a4\ub97c \uc774\uc6a9\ud574 \ub370\uc774\ud130\ub97c \uc800\uc7a5\ud558\ub294 \uc608\uc81c \ucf54\ub4dc\uc785\ub2c8\ub2e4.<\/p>\n
let serviceName = \"com.example.myapp\"\n\nlet query: [String: Any] = [\n kSecClass as String: kSecClassGenericPassword,\n kSecAttrService as String: serviceName,\n kSecAttrAccount as String: \"myaccount\",\n kSecValueData as String: \"mypassword\".data(using: .utf8)!\n]\n\nlet status = SecItemAdd(query as CFDictionary, nil)<\/code><\/pre>\n\uc704 \ucf54\ub4dc\uc5d0\uc11c\ub294 kSecAttrService\ub97c \uc774\uc6a9\ud574 \uc11c\ube44\uc2a4 \uc774\ub984\uc744 \uc9c0\uc815\ud569\ub2c8\ub2e4. \uc774\ub807\uac8c \uc9c0\uc815\ub41c \uc11c\ube44\uc2a4\ub294 \ub3d9\uc77c\ud55c \uc571\uc5d0\uc11c \uacf5\uc720\ub429\ub2c8\ub2e4.<\/p>\n
\ub2e4\uc74c\uc740 Keychain \uc11c\ube44\uc2a4\ub97c \uc774\uc6a9\ud574 \ub370\uc774\ud130\ub97c \uac80\uc0c9\ud558\ub294 \uc608\uc81c \ucf54\ub4dc\uc785\ub2c8\ub2e4.<\/p>\n
let serviceName = \"com.example.myapp\"\n\nlet query: [String: Any] = [\n kSecClass as String: kSecClassGenericPassword,\n kSecAttrService as String: serviceName,\n kSecAttrAccount as String: \"myaccount\",\n kSecMatchLimit as String: kSecMatchLimitOne,\n kSecReturnData as String: true\n]\n\nvar result: AnyObject?\nlet status = SecItemCopyMatching(query as CFDictionary, &result)\n\nif status == errSecSuccess, let data = result as? Data {\n let password = String(data: data, encoding: .utf8)\n}<\/code><\/pre>\n\uc774 \ucf54\ub4dc\uc5d0\uc11c\ub294 \uc704\uc640 \ub9c8\ucc2c\uac00\uc9c0\ub85c kSecAttrService\ub97c \uc774\uc6a9\ud574 \uc11c\ube44\uc2a4 \uc774\ub984\uc744 \uc9c0\uc815\ud569\ub2c8\ub2e4.<\/p>\n
\ub2e4\uc74c\uc740 \uc5d1\uc138\uc2a4 \uadf8\ub8f9 \uae30\ub2a5\uc744 \uc774\uc6a9\ud558\ub294 \ubc29\ubc95\uc5d0 \ub300\ud574 \uc54c\uc544\ubcf4\uaca0\uc2b5\ub2c8\ub2e4. \uc571\uc5d0\uc11c \uc5d1\uc138\uc2a4 \uadf8\ub8f9\uc744 \uc9c0\uc815\ud558\uba74 \ub3d9\uc77c\ud55c \uadf8\ub8f9\uc5d0 \uc18d\ud55c \uc571\ub07c\ub9ac \ub370\uc774\ud130 \uacf5\uc720\uac00 \uac00\ub2a5\ud569\ub2c8\ub2e4. \ub2e4\uc74c\uc740 \uc5d1\uc138\uc2a4 \uadf8\ub8f9\uc744 \uc9c0\uc815\ud574 \ub370\uc774\ud130\ub97c \uc800\uc7a5\ud558\ub294 \uc608\uc81c \ucf54\ub4dc\uc785\ub2c8\ub2e4.<\/p>\n
let accessGroup = \"ABCDEFG123.com.example.myapp\"\n\nlet query: [String: Any] = [\n kSecClass as String: kSecClassGenericPassword,\n kSecAttrAccount as String: \"myaccount\",\n kSecValueData as String: \"mypassword\".data(using: .utf8)!,\n kSecAttrAccessGroup as String: accessGroup\n]\n\nlet status = SecItemAdd(query as CFDictionary, nil)<\/code><\/pre>\n\uc704 \ucf54\ub4dc\uc5d0\uc11c\ub294 kSecAttrAccessGroup\uc744 \uc774\uc6a9\ud574 \uc5d1\uc138\uc2a4 \uadf8\ub8f9\uc744 \uc9c0\uc815\ud569\ub2c8\ub2e4.<\/p>\n
\ub2e4\uc74c\uc740 \uc5d1\uc138\uc2a4 \uadf8\ub8f9\uc744 \uc774\uc6a9\ud574 \ub370\uc774\ud130\ub97c \uac80\uc0c9\ud558\ub294 \uc608\uc81c \ucf54\ub4dc\uc785\ub2c8\ub2e4.<\/p>\n
let accessGroup = \"ABCDEFG123.com.example.myapp\"\n\nlet query: [String: Any] = [\n kSecClass as String: kSecClassGenericPassword,\n kSecAttrAccount as String: \"myaccount\",\n kSecMatchLimit as String: kSecMatchLimitOne,\n kSecReturnData as String: true,\n kSecAttrAccessGroup as String: accessGroup\n]\n\nvar result: AnyObject?\nlet status = SecItemCopyMatching(query as CFDictionary, &result)\n\nif status == errSecSuccess, let data = result as? Data {\n let password = String(data: data, encoding: .utf8)\n}<\/code><\/pre>\n\uc774 \ucf54\ub4dc\uc5d0\uc11c\ub3c4 \uc704\uc640 \ub9c8\ucc2c\uac00\uc9c0\ub85c kSecAttrAccessGroup\uc744 \uc774\uc6a9\ud574 \uc5d1\uc138\uc2a4 \uadf8\ub8f9\uc744 \uc9c0\uc815\ud569\ub2c8\ub2e4.<\/p>\n
iOS Keychain \ubcf4\uc548 \ubaa8\ubc94 \uc0ac\ub840 \ubc0f \uc8fc\uc758\uc810<\/h2>\n
Keychain\uc740 iOS\uc5d0\uc11c \uc81c\uacf5\ud558\ub294 \uace0\uae09 \ubcf4\uc548 \uae30\ub2a5 \uc911 \ud558\ub098\uc785\ub2c8\ub2e4. \uc571\uc5d0\uc11c \uc911\uc694\ud55c \uc815\ubcf4\ub97c \uc548\uc804\ud558\uac8c \uc800\uc7a5\ud558\uace0 \uad00\ub9ac\ud558\uae30 \uc704\ud574\uc11c\ub294 Keychain\uc744 \uc774\uc6a9\ud574\uc57c \ud569\ub2c8\ub2e4. \uc774\ubc88\uc5d0\ub294 Keychain\uc744 \uc774\uc6a9\ud560 \ub54c \uc8fc\uc758\ud574\uc57c \ud560 \uc0ac\ud56d\ub4e4\uc5d0 \ub300\ud574 \uc54c\uc544\ubcf4\uaca0\uc2b5\ub2c8\ub2e4.<\/p>\n
\ubcf4\ud638 \ud074\ub798\uc2a4 \uc124\uc815<\/h3>\n
Keychain\uc5d0\uc11c \ub370\uc774\ud130\ub97c \uc800\uc7a5\ud560 \ub54c\ub294 \ubcf4\ud638 \ud074\ub798\uc2a4\ub97c \uc9c0\uc815\ud574\uc57c \ud569\ub2c8\ub2e4. \ubcf4\ud638 \ud074\ub798\uc2a4\ub294 \ub370\uc774\ud130\ub97c \uc5b4\ub5bb\uac8c \ubcf4\ud638\ud560 \uac83\uc778\uc9c0\ub97c \uacb0\uc815\ud558\ub294\ub370, \ubcf4\ud638 \ud074\ub798\uc2a4\uac00 \ub192\uc744\uc218\ub85d \ubcf4\uc548\uc774 \uac15\ud654\ub429\ub2c8\ub2e4. iOS\uc5d0\uc11c\ub294 \ub2e4\uc74c\uacfc \uac19\uc740 \ubcf4\ud638 \ud074\ub798\uc2a4\ub97c \uc81c\uacf5\ud569\ub2c8\ub2e4.<\/p>\n
\n- kSecAttrAccessibleWhenUnlocked: \uc7a0\uae08 \ud574\uc81c\ub41c \uc0c1\ud0dc\uc5d0\uc11c\ub9cc \uc811\uadfc \uac00\ub2a5<\/li>\n
- kSecAttrAccessibleAfterFirstUnlock: \ucc98\uc74c \uc7a0\uae08 \ud574\uc81c \uc774\ud6c4\uc5d0\ub9cc \uc811\uadfc \uac00\ub2a5<\/li>\n
- kSecAttrAccessibleWhenUnlockedThisDeviceOnly: \uac19\uc740 \uae30\uae30\uc5d0\uc11c\ub9cc \uc811\uadfc \uac00\ub2a5<\/li>\n
- kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly: \uac19\uc740 \uae30\uae30\uc5d0\uc11c\ub9cc \uc811\uadfc \uac00\ub2a5<\/li>\n
- kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly: \uc554\ud638 \uc124\uc815\uc774 \ub418\uc5b4 \uc788\uace0, \uac19\uc740 \uae30\uae30\uc5d0\uc11c\ub9cc \uc811\uadfc \uac00\ub2a5<\/li>\n<\/ul>\n
\ubcf4\ud638 \ud074\ub798\uc2a4\ub294 \uc571\uc758 \ubcf4\uc548 \uc694\uad6c \uc0ac\ud56d\uc5d0 \ub9de\uac8c \uc124\uc815\ud574\uc57c \ud569\ub2c8\ub2e4. \uc608\ub97c \ub4e4\uc5b4, \uc0ac\uc6a9\uc790\uac00 \ub85c\uadf8\uc778\ud55c \ud6c4\uc5d0\ub9cc \ub370\uc774\ud130\uc5d0 \uc811\uadfc\ud574\uc57c \ud55c\ub2e4\uba74 kSecAttrAccessibleWhenUnlocked\uc744 \uc0ac\uc6a9\ud558\uba74 \ub429\ub2c8\ub2e4.<\/p>\n
\uc5d1\uc138\uc2a4 \uc81c\ud55c \uc124\uc815<\/h3>\n
Keychain\uc5d0\uc11c \ub370\uc774\ud130\ub97c \uc800\uc7a5\ud560 \ub54c\ub294 \uc5d1\uc138\uc2a4 \uc81c\ud55c\ub3c4 \uc124\uc815\ud560 \uc218 \uc788\uc2b5\ub2c8\ub2e4. \uc5d1\uc138\uc2a4 \uc81c\ud55c\uc744 \uc124\uc815\ud558\uba74 \ud2b9\uc815\ud55c \uc870\uac74\uc5d0\uc11c\ub9cc \ub370\uc774\ud130\uc5d0 \uc811\uadfc\uc774 \uac00\ub2a5\ud574\uc9d1\ub2c8\ub2e4. iOS\uc5d0\uc11c\ub294 \ub2e4\uc74c\uacfc \uac19\uc740 \uc5d1\uc138\uc2a4 \uc81c\ud55c\uc744 \uc81c\uacf5\ud569\ub2c8\ub2e4.<\/p>\n
\n- kSecAttrAccessControl: \ucd94\uac00\uc801\uc778 \uc5d1\uc138\uc2a4 \uc81c\ud55c\uc744 \uc124\uc815\ud560 \uc218 \uc788\ub294 \uac1d\uccb4<\/li>\n
- kSecAttrAccessGroup: \uac19\uc740 \uc5d1\uc138\uc2a4 \uadf8\ub8f9\uc5d0 \uc18d\ud55c \uc571\ub07c\ub9ac \ub370\uc774\ud130 \uacf5\uc720 \uac00\ub2a5<\/li>\n<\/ul>\n
\uc5d1\uc138\uc2a4 \uc81c\ud55c\uc740 \ubcf4\ud638 \ud074\ub798\uc2a4\ubcf4\ub2e4 \ub354 \uac15\ub825\ud55c \ubcf4\uc548 \uae30\ub2a5\uc744 \uc81c\uacf5\ud569\ub2c8\ub2e4. \uc554\ud638\ub97c \uc785\ub825\ud574\uc57c\ub9cc \ub370\uc774\ud130\uc5d0 \uc811\uadfc\ud560 \uc218 \uc788\ub3c4\ub85d \uc124\uc815\ud560 \uc218\ub3c4 \uc788\uc2b5\ub2c8\ub2e4.<\/p>\n
\ud0a4 \uccb4\uc778 \uc811\uadfc \uad8c\ud55c \uc124\uc815<\/h3>\n
Keychain\uc5d0\uc11c \ub370\uc774\ud130\ub97c \uc800\uc7a5\ud560 \ub54c\ub294 \ud574\ub2f9 \ub370\uc774\ud130\uc5d0 \uc811\uadfc\ud560 \uc218 \uc788\ub294 \uc571\uc744 \uc124\uc815\ud560 \uc218 \uc788\uc2b5\ub2c8\ub2e4. iOS\uc5d0\uc11c\ub294 \ub2e4\uc74c\uacfc \uac19\uc740 \ud0a4 \uccb4\uc778 \uc811\uadfc \uad8c\ud55c\uc744 \uc81c\uacf5\ud569\ub2c8\ub2e4.<\/p>\n
\n- kSecAttrAccessGroup: \uac19\uc740 \uc5d1\uc138\uc2a4 \uadf8\ub8f9\uc5d0 \uc18d\ud55c \uc571<\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"
iOS \uc571 \ubcf4\uc548 \uac15\ud654\ub97c \uc704\ud55c Keychain \uc0ac\uc6a9 \ubc29\ubc95<\/p>\n","protected":false},"author":1,"featured_media":33704,"comment_status":"closed","ping_status":"","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1957],"tags":[2119,2104,6040,2457,2455,6041,2277,3291],"class_list":["post-37307","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-development","tag-api","tag-data","tag-ios","tag-load","tag-query","tag-swift","tag-using","tag-3291"],"acf":[],"_links":{"self":[{"href":"https:\/\/8gfg.shop\/blog\/wp-json\/wp\/v2\/posts\/37307","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/8gfg.shop\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/8gfg.shop\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/8gfg.shop\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/8gfg.shop\/blog\/wp-json\/wp\/v2\/comments?post=37307"}],"version-history":[{"count":1,"href":"https:\/\/8gfg.shop\/blog\/wp-json\/wp\/v2\/posts\/37307\/revisions"}],"predecessor-version":[{"id":37347,"href":"https:\/\/8gfg.shop\/blog\/wp-json\/wp\/v2\/posts\/37307\/revisions\/37347"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/8gfg.shop\/blog\/wp-json\/wp\/v2\/media\/33704"}],"wp:attachment":[{"href":"https:\/\/8gfg.shop\/blog\/wp-json\/wp\/v2\/media?parent=37307"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/8gfg.shop\/blog\/wp-json\/wp\/v2\/categories?post=37307"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/8gfg.shop\/blog\/wp-json\/wp\/v2\/tags?post=37307"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}