- What Keychains are
- 목적
- 패스워드, 코드 값 등의 작은 비밀 값을 안정하게 저장하기 위함
- 특정 유저와 애플리케이션을 위한 제한된 접근
- 오프라인 공격에 대한 보호
- 유저의 컨트롤 하에서의 비밀 저장
- 표준화된 고수준 솔루션
- 특징 및 기능
- 매우 특수화된 데이터베이스
- 메타 데이터(attributes)
- 보호되는 데이터(payload)
- 메타데이터를 통한 효율적인 검색
- 작은 크기의 단일데이터 접근에 효율적
- 큰 데이터를 여러번 접근하는 것은 비효율적이다.
- 왜 이걸 써야 되지?
- 하드웨어와 긴밀하게 연결되어 있다.
- 액세스 컨트롤을 제공한다.
- 앱 간에 공유도 통제되고 있다.
- 파일로 하면 쉽게 스캔, 카피, 복제가 가능하다.
- 직접하면 탈옥등의 이슈에 대응하기 힘들다.
- How to Use Them
// 키체인 아이템 생성
NSData* secret = [@"top secret" dataWithEncoding: NSUTF8StringEncoding];
NSDictionary* query = @ {
(id) kSecClass: (id)kSecClassGenericPassword,
(id) kSecAttrService: @"myservice",
(id) kSecAttrAccount: @"account name here",
(id) kSecValueData: secret,
};
OSStatus status = SecItemAdd((CFDictionaryRef)query, NULL);
// 룩업
NSDictionary* query = @ {
(id) kSecClass: (id)kSecClassGenericPassword,
(id) kSecAttrService: @"myservice",
(id) kSecAttrAccount: @"account name here",
(id) kSecReturnData: @YES,
};
NSData *data = NULL
OSStatus status = SecItemCopyMatching((CFDictionaryRef) query, (CFTypeRef*) &data);
NSDictionary* query = @ {
(id) kSecClass: (id)kSecClassGenericPassword,
(id) kSecAttrService: @"myservice",
(id) kSecAttrAccount: @"account name here",
};
NSDictionary* changes = @{...};
// 업데이트 - 삭제후 다시 삽입하지 말라
OSStatus SecItemUpdate((CFDictionaryRef) query, (CFDictionaryRef) changes);
// 삭제
OSStatus status = SecItemDelete((CFDictionaryRef) query);
- 키체인에 중복된 아이템을 만들 수는 없다.
- 키체인 저장 워크플로우
NSData* password = nil;
if (SecItemCopyMatching(..., &password) == noErr) {
if (패스워드가 동작한다.) {
great!
} else {
password = 다른 패스워드;
if (바뀐 패스워드가 괜찮다) {
SecItemUpdate(...);
}
}
} else {
password = get from user;
if (passwork works) {
SetItemAdd(...);
}
}
- 고려사항
- 저장하기 전에 사용해보라
- 패스워드가 잘못된건지, 동작 환경이 잘못된건지를 구분해야 된다.
- 다른 곳에서 패스워드가 바뀌어서 현재 키체인의 패스워드가 유효하지 않은 상황에 대비해야 한다.
- 실패 상황에 항상 대비해야 한다.
- 시크릿까지 필요한 데이터인지도 고민해보라
- 사용한 비밀 데이터는 메모리에 저장해놓거나 어디로 전송하지 말고, 쓰고 버려라
- iOS Specifics
- API는 동일
- 아이폰이 잠금 해제될 때 키체인도 잠금 해제 된다.
- 키체인 그룹에 의해서 다른 앱과 공유될 수 있다.
- 키체인 그룹 이름은 팀 ID로 시작해야만 한다.
- 데이터 보호 수준 설정 가능: kSecAttrAccessible
- WhenUnlocked
- AfterFirstUnlock -> 백그라운드에서 해당 데이터를 사용할 때 유용
- 백업과 마이그레이션
- 시스템에 의해 수행됨
- 같은 디바이스에 대한 복구는 자동으로 수행됨
- 다른 디바이스로 마이그레이션을 위해서는 암호화된 백업이 필요하다.
- 디버깅
- iOS keychain을 위한 디버깅 툴은 없다. -> 앱 안에서 디버깅 코드를 쓰는 수 밖에는…
- 인자 딕셔너리 돌려쓰는 것은 신중하라. -> 거의 비슷하지만 조금은 다를 수 있다.
- OSX Specifics
- SecItem API가 추천되고, 레거시도 원하면 사용은 가능하다.
- 키체인은 파일로 존재한다.
- 로그인 패스워드로 잠금이 해제된다.
- POSIX 퍼미션을 따른다.
- 키체인 공유는 파일시스템을 통해서 이루어진다.
- login.keychain - 유저별
- System.keychain - 전체 시스템용
- 각 아이템은 ACL(Access Control List)를 가짐
- 이는 아이템 생성시 설정한다.
- 업데이트로 바꿀 수는 있지만, 권장하지는 않는다.
- 키체인을 해제 할 때 OS X는 프롬프트를 띄운다.
- GUI가 없는 상황에서는 실패한다.
- Security(1)을 활용하자
- 마이그레이션
- 파일이기 때문에 일반적인 방법대로 마이그레이션 하면 된다.
- 데몬에서의 키체인
- 시스템 키체인이 기본 키체인
- 유저 키체인은 사용 불가능
- 쓰기 작업은 루트 권한 필요
- 역시 security(1) 필요
- iCloud Keychain
- iOS와 OS X 장비 간에 싱크 가능
- SecItem API를 사용해야 된다. -> 괜히 커스텀한다고 이것저것 붙이지 말라