ํ‹ฐ์Šคํ† ๋ฆฌ ๋ทฐ

iOS

[iOS] Keychain

Neoguri๐Ÿฆ 2024. 11. 4. 00:22

 

์•ˆ๋…•ํ•˜์„ธ์š”?

๋„ˆ๊ตฌ๋ฆฌ์ž…๋‹ˆ๋‹ค.

 

์ €๋ฒˆ ํฌ์ŠคํŒ…์— ์ด์–ด

์ด๋ฒˆ์—๋Š” keychain์— ๋Œ€ํ•ด ์•Œ์•„๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

 

Keychain Service๋ž€?

ํ‚ค์ฒด์ธ ์„œ๋น„์Šค๋Š” ํ‚ค์ฒด์ธ์ด๋ผ๋Š” ์•”ํ˜ธํ™”๋œ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ์‚ฌ์šฉ์ž ๋ฐ์ดํ„ฐ๋ฅผ ์•ˆ์ „ํ•˜๊ฒŒ ์ €์žฅํ•  ์ˆ˜ ์žˆ๋Š” ๋ฉ”์ปค๋‹ˆ์ฆ˜์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

ํ‚ค์ฒด์ธ์„ ์‚ฌ์šฉํ•  ๊ฒฝ์šฐ ์•ฑ์„ ์‚ญ์ œํ•˜๋”๋ผ๋„ ์˜๊ตฌ์ ์œผ๋กœ ๋ฐ์ดํ„ฐ๊ฐ€ ๋‚จ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

 

 

๋น„๋ฐ€๋ฒˆํ˜ธ, cryptographic keys ๋“ฑ ์‚ฌ์šฉ์ž๊ฐ€ ์ค‘์š”ํ•˜๊ฒŒ ์ƒ๊ฐํ•˜๋Š” ๋ฐ์ดํ„ฐ๋ฅผ 

์•ˆ์ „ํ•˜๊ฒŒ ์ €์žฅํ•  ์ˆ˜ ์žˆ๋„๋ก ๋„์™€์ค๋‹ˆ๋‹ค.

 

Keychain Item

ํ‚ค์ฒด์ธ์— ์ €์žฅํ•˜๋ ค๋ฉด ์ €์žฅํ•  ์ˆ˜ ์žˆ๋Š” ํ˜•ํƒœ๋กœ ๋ฐ”๊ฟ”์ฃผ์–ด์•ผ ํ•˜๋Š”๋ฐ,

๊ทธ ํ˜•ํƒœ๋ฅผ Keychain Item์ด๋ผ๊ณ  ํ•ฉ๋‹ˆ๋‹ค.

 

 

์œ„์˜ ๊ทธ๋ฆผ์„ ๋ณด๋ฉด Data์™€ ํ•จ๊ป˜ Attributes๋„ ํ•จ๊ป˜ ์ €์žฅ ๋˜๋Š”๋ฐ

๋ฐ์ดํ„ฐ์— ์ ‘๊ทผ์„ฑ์„ ๊ด€๋ฆฌํ•˜๊ณ  ๊ฒ€์ƒ‰ํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•˜๋Š” ์—ญํ• ์„ ํ•ฉ๋‹ˆ๋‹ค.

 

ํ‚ค์ฒด์ธ ์„œ๋น„์Šค๋Š” ๋ฐ์ดํ„ฐ ์•”ํ˜ธํ™”์™€ ์ €์žฅ์„ ํ‚ค์ฒด์ธ์— ์ฒ˜๋ฆฌํ•˜๋ฉฐ, ์ด๋Š” ๋””์Šคํฌ์— ์ €์žฅ๋œ ์•”ํ˜ธํ™”๋œ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์ž…๋‹ˆ๋‹ค.

์ดํ›„ ์Šน์ธ๋œ ํ”„๋กœ์„ธ์Šค๋งŒ์ด ํ‚ค์ฒด์ธ ์„œ๋น„์Šค๋ฅผ ํ†ตํ•ด ํ•ญ๋ชฉ์„ ์ฐพ์•„ ๋ฐ์ดํ„ฐ๋ฅผ ๋ณตํ˜ธํ™”ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

 

์–ด๋–ป๊ฒŒ ์‚ฌ์šฉํ•˜๋Š”๊ฐ€?

๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅํ•˜๊ณ  ๋ถˆ๋Ÿฌ์˜ฌ ๋•Œ ์–ด๋–ป๊ฒŒ ์‚ฌ์šฉํ•˜๋Š”์ง€ ์•Œ์•„๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

๋ฐ”๋กœ ์‚ฌ์šฉ๋ฒ•์œผ๋กœ ๊ฐ€๊ธฐ์ „์— ๋จผ์ € ์•Œ์•„์•ผ ํ•  ์ •๋ณด๊ฐ€ ์žˆ์–ด ๋จผ์ € ์•Œ์•„๋ณด๋„๋ก ํ• ๊ฒŒ์š”!

 

CFDictionary

keychain์— ๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅํ•˜๊ธฐ ์œ„ํ•ด์„œ ๋ฐ์ดํ„ฐ๋ฅผ ์ „๋‹ฌ์„ ํ•ด์•ผํ•˜๋Š”๋ฐ

๋ฐ”๋กœ ์ด ํ˜•ํƒœ๋กœ ์ „๋‹ฌํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

 

kSecClass

๋˜ ์ „๋‹ฌํ•  ๋ฐ์ดํ„ฐ์— ๋Œ€ํ•œ ํƒ€์ž…์„ kSecClass ํƒ€์ž…์œผ๋กœ ์ „๋‹ฌํ•ด ์ค„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

  • kSecClassGenericPassword: ์ผ๋ฐ˜์ ์œผ๋กœ ์‚ฌ์šฉ๋˜๋Š” ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ์ €์žฅํ•  ๋•Œ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ: ์•ฑ ์‚ฌ์šฉ์ž ๋น„๋ฐ€๋ฒˆํ˜ธ.
  • kSecClassInternetPassword: ์ธํ„ฐ๋„ท ๋น„๋ฐ€๋ฒˆํ˜ธ, ์„œ๋ฒ„๋‚˜ ์›น์‚ฌ์ดํŠธ ๋กœ๊ทธ์ธ ์ •๋ณด ์ €์žฅ์— ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.
  • kSecClassCertificate: ๋””์ง€ํ„ธ ์ธ์ฆ์„œ๋ฅผ ์ €์žฅํ•  ๋•Œ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.
  • kSecClassKey: ์•”ํ˜ธํ™” ํ‚ค๋ฅผ ์ €์žฅํ•  ๋•Œ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.
  • kSecClassIdentity: ์ธ์ฆ์„œ์™€ ํ‚ค ์Œ์„ ์ €์žฅํ•  ๋•Œ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

 

 

๊ทธ๋Ÿผ ์ด์ œ ์‹ค์ œ๋กœ ์‚ฌ์šฉํ•˜๋Š” ์ฝ”๋“œ์ž…๋‹ˆ๋‹ค.

 

 // ํ‚ค์ฒด์ธ์— ๋ฐ์ดํ„ฐ ์ €์žฅ
    func save(_ data: Data, forKey key: String) {
        let query: [String: Any] = [
            kSecClass as String: kSecClassGenericPassword,
            kSecAttrAccount as String: key,
            kSecValueData as String: data
        ]
        
        // ๊ธฐ์กด ๋ฐ์ดํ„ฐ๊ฐ€ ์žˆ์œผ๋ฉด ์‚ญ์ œ
        SecItemDelete(query as CFDictionary)
        
        // ์ƒˆ ๋ฐ์ดํ„ฐ ์ €์žฅ
        let status = SecItemAdd(query as CFDictionary, nil)
        if status != errSecSuccess {
            print("Error saving data: \(status)")
        }
    }
    
    // ํ‚ค์ฒด์ธ์—์„œ ๋ฐ์ดํ„ฐ ์ฝ๊ธฐ
    func load(forKey key: String) -> Data? {
        let query: [String: Any] = [
            kSecClass as String: kSecClassGenericPassword,
            kSecAttrAccount as String: key,
            kSecReturnData as String: true,
            kSecMatchLimit as String: kSecMatchLimitOne
        ]
        
        var dataTypeRef: AnyObject?
        let status = SecItemCopyMatching(query as CFDictionary, &dataTypeRef)
        
        if status == errSecSuccess {
            return dataTypeRef as? Data
        } else {
            print("Error loading data: \(status)")
            return nil
        }
    }
    
    // ํ‚ค์ฒด์ธ์—์„œ ๋ฐ์ดํ„ฐ ์—…๋ฐ์ดํŠธ
    func update(_ data: Data, forKey key: String) {
        let query: [String: Any] = [
            kSecClass as String: kSecClassGenericPassword,
            kSecAttrAccount as String: key
        ]
        
        let attributes: [String: Any] = [
            kSecValueData as String: data
        ]
        
        let status = SecItemUpdate(query as CFDictionary, attributes as CFDictionary)
        
        if status == errSecItemNotFound {
            // ํ•ญ๋ชฉ์ด ์กด์žฌํ•˜์ง€ ์•Š์œผ๋ฉด ์ €์žฅ
            save(data, forKey: key)
            print("Item not found, so saved new item.")
        } else if status != errSecSuccess {
            print("Error updating data: \(status)")
        } else {
            print("Data updated successfully.")
        }
    }
    
    // ํ‚ค์ฒด์ธ์—์„œ ๋ฐ์ดํ„ฐ ์‚ญ์ œ
    func delete(forKey key: String) {
        let query: [String: Any] = [
            kSecClass as String: kSecClassGenericPassword,
            kSecAttrAccount as String: key
        ]
        
        let status = SecItemDelete(query as CFDictionary)
        if status != errSecSuccess {
            print("Error deleting data: \(status)")
        }
    }

 

์—ฌ๊ธฐ์„œ ์ฃผ์˜ํ•  ์ ์ด ์žˆ๋Š”๋ฐ

SecItemAdd ํ•จ์ˆ˜๋Š” ์Šค๋ ˆ๋“œ๋ฅผ ๋ธ”๋ฝ ์‹œํ‚ค๊ธฐ ๋•Œ๋ฌธ์— 

๋ฉ”์ธ ์Šค๋ ˆ๋“œ์—์„œ ๋‹ค๋ฃฐ ๊ฒฝ์šฐ UI๊ฐ€ ๋ฉˆ์ถ”๋Š” ๋ฌธ์ œ๋ฅผ ๋ฐœ์ƒ์‹œํ‚ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋”ฐ๋ผ์„œ background ์Šค๋ ˆ๋“œ๋‚˜ aync ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

 

 

๊ธ€ ์ฝ์–ด์ฃผ์…”์„œ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค.

 

 

์ฐธ๊ณ  : https://developer.apple.com/documentation/security/keychain-services

 

Keychain services | Apple Developer Documentation

Securely store small chunks of data on behalf of the user.

developer.apple.com

 

๋Œ“๊ธ€
๊ณต์ง€์‚ฌํ•ญ
์ตœ๊ทผ์— ์˜ฌ๋ผ์˜จ ๊ธ€
์ตœ๊ทผ์— ๋‹ฌ๋ฆฐ ๋Œ“๊ธ€
Total
Today
Yesterday
๋งํฌ
ยซ   2026/03   ยป
์ผ ์›” ํ™” ์ˆ˜ ๋ชฉ ๊ธˆ ํ† 
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31
๊ธ€ ๋ณด๊ด€ํ•จ