iOS

KeyChain vs UserDefaults(2)

스엠 2022. 11. 22. 14:06

KeyChain

이번에는 저번 UserDefaults에 이어서 KeyChain에 대해서 알아보겠습니다. 

 

UserDefaults는 저번 시간에  .plist 파일에 key-value의 형태로 저장된다고 했습니다.

그리고 보안성도 좋지는 않다고 설명드렸습니다. 

 

그럼 KeyChain은 어떤지 한번 알아보겠습니다. 

 

1. 구성도 - KeyChain Service API 

애플의 공식적인 문서를 보면 KeyChain에 대하여 다음과 같이 정의하고 있습니다. 

The keychain services API helps you solve this problem by giving your app a mechanism to store small bits of user data in an encrypted database called a keychain.

 

간단히 말하면 작은 비트의 데이터들을 암호화하여 KeyChain이라는 데이터 베이스에 저장한다는 것 입니다. 

사진과 같이 비밀번호, 암호화 키, 인증서, 노트 등 여러가지를 저장할 수 있는 것으로 보입니다. 

여기서 UserDefaults와의 차이점은 UserDefault는 데이터가 앱에 국한되어 있는 반면에 KeyChain은 디바이스 자체에 저장된다는 것입니다. 따라서 여러앱(공유하려면 따로 설정이 필요합니다.)에서 같은 정보를 참조하고 저장할 수 있다는 것입니다. 또한 디바이스 자체에 저장되는 것이므로 앱을 제거해도 KeyChain에 저장된 데이터는 사라지지 않습니다. 

 

2. 구성도 - KeyChain Item

애플의 공식적인 문서를 보면 KeyChain Item에 대하여 다음과 같이 정의하고 있습니다.

When you want to store a secret such as a password or cryptographic key, you package it as a keychain item. Along with the data itself, you provide a set of publicly visible attributes both to control the item’s accessibility and to make it searchable. 

 

키체인에 저장되는 data의 단위를 keyChain Item이라고 부른다고 합니다. 또한 KeyChain Item을 저장할때 아이템의 접근성과 검색을 가능하게 하기 위한 공개적으로 보이는 속성들을 설정할 수 있습니다.

그림에서 보면 Data는 암호화가 되고 Attributes는 그대로 Item에 포함되는 것을 볼 수 있습니다.

 

3. 구성도 - KeyChain Item 의 종류

KeyChain으로써 저장할 수 있는 Data의 종류들 입니다. 

이것 말고도 위에서 데이터 말고 Attributes를 설정할 수 있다고 했습니다. 

Attributes에도 따로 설정할 수 있는 키 값이 존재합니다. 이것에 대한 것은 분량이 많은 관계로 공식 홈페이지에서 상황에 따라 필요로하는 Attributes을 사용하면 될 것 같습니다. 

https://developer.apple.com/documentation/security/keychain_services/keychain_items/item_attribute_keys_and_values

 

Apple Developer Documentation

 

developer.apple.com

 

 

4. KeyChain 관련 오류들

키체인에서 데이터를 접근하거나 저장할 때 발생할 수 있는 오류 Key들입니다. 

이 Key에 따라 예외처리를 하면 될것 같습니다. 

  • errSecSuccess : 정상 - 0
  • errSecUnimplemented : 호출 함수 미구현 -4
  • errSecParam : 매개변수 문제 -50
  • errSecAllocate : 메모리 할당 실패 -108
  • errSecNotAvailable : 신뢰할만한 결과가 없음 -25291
  • errSecAuthFailed : 인증 실패 -25293
  • errSecDuplicateItem : 아이템이 이미 존재함 -25299
  • errSecItemNotFound : 아이템 찾을 수 없음 -25300
  • errSecInteractionNotAllowed : 보안서버와 연결이 불가능 -25308
  • errSecDecode : 제공된 데이터를 복호화 할 수 없음 -26275

 

5. KeyChain Item 생성

Ios에서는 KeyChain이 하나밖에 없으므로 keyChain(aka 데이터베이스)을 또 생성 할 수는 없습니다.

하지만 MacOs에서는 KeyChain이 여러개 있을 수 있습니다. 이점 참고 하시길 바랍니다.

 

이제 예시로 일반 암호를 저장하는 KeyChain item을 생성해보겠습니다.

kSecClass : 어떤 타입의 Item인지 결정 

kSecAttrService : 이 암호가 어떤 앱 혹은 웹에서 사용되는지 결정 // 주로 번들아이디 같은 유일성을 가지는 것을 사용하면 될 것 같습니다. kSecClassGenericPassword에만 있는 속성입니다. 

kSecAttrAccount : 계정의 이름 // kSecClassGenericPassword와 kSecClassInternetPassword에만 있는 속성입니다. 

kSecValueData: 저장할 데이터 // Data형태로 저장을 해야 합니다. 

 

일단 데이터베이스에 저장을 하는 것이니 query를 작성해 주셔야 합니다. 

query에 쓸수 있는 kSecAttr들이 정말 다양하니 공식 홈페이지에서 필요한 것을 찾아서 적용해 사용하면 됩니다. 

 

이렇게 쿼리를 만들고 나서 SecItemAdd(:)라는 함수를 통하여 데이터베이스에 저장합니다. 

이때 반환값으로써 errorCode을 반환합니다. 예제에서는 errSecSuccess 즉 성공했을때 True를 반환하여 데이터 저장에 성공 했음을 알려줍니다. 

 

6. KeyChain Item 가져오기 

 

이번에는 accountName을 가지고 keyChain에 있는 password를 다시 꺼내오겠습니다.

아이템을 저장할때 처럼 꺼내올때도 query를 만들어서 꺼내와야 합니다. 

kSecAttrService 와 kSecAttrAccount는 KeyChain Item 생성할때 설정한 값으로 하면 됩니다.

kSecReturnAttributes : item의 속성을 가져온다

kSecReturnData : item의 데이터를 가져온다

 

var item : CFTypeRef?

요부분은 swift에서는 잘 쓰지 않는 포인터를 위하여 있습니다. 

SecItemCopyMatching()에서 두번째 인자가 데이터를 담을 변수를 넣는 공간입니다.

existingItem을 보면 acct : test라고 되어 있는 것을 볼 수 있네요. 

sha1은 암호화 관련인 것 같고 sync는 동기성에 관한것 v_Data : xxx로 valueData에 대한 키 값이 있는 것도 보실 수 있습니다.

cdat mdat은 생성날짜 변경날짜? 인것 같습니다.

이처럼 existingItem에 item관련한 key-value형태값을 볼 수 있습니다. 

 

6. KeyChain Item 변경하기 

 

이번에는 Item을 변경해보겠습니다.

 

update할때 한가지 다른점음 searchQuery와 updateQuery입니다.

searchQuery는 변경할 아이템을 찾기 위한 것이고 updateQuery는 찾은 아이템에서 어떤 것들을 변경할지에 대한 것입니다. 

함수는 SecItemUpdate()를 사용하고 첫번째 인자에 searchQuery, 두번째 인자에 updateQuery를 입력하면 됩니다. 

 

6. KeyChain Item 삭제하기

KeyChain Item은 UserDefault와 달리 앱과의 종속성이 있지 않아 앱을 삭제해도 남아 있습니다.

따라서 앱 삭제시 관련된 데이터를 지우기 위해서는 꼭 삭제 명령을 해주어야 합니다. 

 

삭제할때 계정이 몇개 있든지 무관하게 service(앱의 번들아이디)와 관련되어 있으면 삭제하라는 함수 입니다.

이와 별개로 특정 계정 정보만 지우고 싶으면 kSecAttrAccount도 query에 포함하여 지우면 될것 같습니다.

 

 

 

이렇게 해서 기본적으로 keyChain이 무엇인지 또 CRUD를 어떻게 하는지에 대해서 알아보았습니다. 

UserDefault에 비해서 굉장히 복잡한 절차를 가지고 있습니다. 

특히 어떤 Class를 저장하고 가져올 것이냐에 따라 그와 관련된 attribute들이 다르기 때문에 공식 도큐먼트를 계속 보면서 개발해야 하는 번거로움이 있네요. 

 

 

 

'iOS' 카테고리의 다른 글

MVVM (2)  (0) 2022.12.19
MVVM (1) - 바인딩 방법들  (1) 2022.12.09
KeyChain vs UserDefaults(1)  (0) 2022.11.17
some 과 any 그리고 Any?(2)  (0) 2022.10.26
some 과 any 그리고 Any?(1)  (0) 2022.10.12