TIL Notion -> Velog 이전하면서 복습하기
ref) 꼼꼼한 재은씨의 Swift(실전편)
우리는 앱을 사용할 때 계정에 로그인을 하기 위해 인증
을하며, 이 인증
을 통해 사용자에게 많은 자격을 다르게 부여한다
서버로부터 받은 로그인 API의 응답 결과를 보면
user_info
외에도 응답코드(result_code)
와 메세지(error_msg)
, 그리고 토큰 값(refresh_token, access_token)
등이 포함되어 있는 것을 알 수 있습니다
이 중에서 토큰 값은 로그인 API의 핵심이라고 할 수 있는 아주 중요한 항목이다. 일종의 로그인 세션 역할을 하는 값으로, 해당 토큰을 소유한 사람이라면 별도의 자격 증명을 제시하지 않고도 관련 서비스를 사용할 수 있습니다
OAuth 기반 서버에서 인증이 필요한 API를 호출할 때에는 반드시 이 토큰이 함께 전송되어야 합니다
그런데, 인증 토큰을 사용하기 위해서는 어딘가에 저장해두어야 한다. 매번 로그인해서 이 값을 받아올 수는 없으니깐... 인증 토큰을 어디다 저장하는 것이 좋을까?
손쉽게 떠올릴 수 있는 장소는 UserDefault
가 있다. 저장이 간편할 뿐만 아니라 사용하기도 쉽다는 점에서 무척 좋은 장소이다
UserDefault
Xcode에서 매번 보던 Info.plist(프로퍼티 리스트) 파일에서 Key-vlaue로 값이 저장되는 것
참고) UserDefaults
But, 저장하기 편한만큰, 접근이 너무 쉽다는 단점이 있다
그리고 기본적으로는 암호화가 이루어지지도 않는다
Securely store small chunks of data on behalf of the user
Reference) KeyChain Services
그래서 이를 해결해줄 KeyChain
이라는 개념이 있다. 이는 애플 계열의 운영체제에서 동작하는 다양한 응용 프로그램에서 비밀번호나 계정 등 보안이 필요한 요소를 저장하는데 사용하는 암호화된 저장소이다.
iOS뿐만 아니라, macOS, tvOS, watchOS 등에서도 모두 제공된다. 사용하는 곳들이 많아서, 아이클라우드의 로그인 정보가 키 체인을 통해 관리되고 있고, 와이파이의 패스워드도 키 체인에 저장되며, 사파리에 웹사이트별 패스워드 관리할 때에도 키 체인이 사용된다.
샌드박스
외부에서 받은 파일을 바로 실행하지 않고 보호된 영역에서 실행시켜 봄으로써 잘못된 파일과 프로그램이 내부시스템 전체에 악영향을 주는지 확인하는 기술. 이를 확장해서 iOS에서는 App 간에 데이터 공유가 불가능하도록 격리된 각자의 샌드박스 공간을 제공하는데, iOS 시스템 자체에는 파일을 함부로 쓸 수 없지만 샌드박스 내부에서는 파일 쓰기가 허용된다.
kSecClassInternetPassword
kSecClassCertificate
kSecClassGenericPassword
등이 있습니다키 체인 아이템을 정의할 때에는 저장할 데이터에 맞는 아이템 클래스를 선택해야 한다. 각 아이템 클래스는 저장값의 특성에 따라 서로 다른 어트리뷰트를 제공하기 때문이다!!
앞에서 말했듯이, KeyChain은 파일 시스템에 저장된 데이터베이스와 크게 다를 것이 없는데, 그래서 데이터베이스의 핵심인 CRUD에 크게 벗어나지 않는다. 그러니깐, 이것에 대응되는 메소드가 쓰인다는 것이겠지??
키 체인 쿼리(Key Chain Query)
위 메소드들은 모두 C스타일로 코딩되어 있으며,키 체인 쿼리
라고 불리는 CFDictionary 타입의 데이터 집합을 인자값으로 받아 사용합니다. 데이터베이스로 치자면 테이블과 키 값, 저장할 내용 등이 모두 어우러진 SQL문에 해당하는 셈이다. 우리는 저장할 데이터, 아이템 클래스, 서비스명 등을 키 체인 쿼리에 정의한 다음, 목적에 맞는 함수를 호출하면 원하는 CRUD 작업을 처리하게 됩니다.
import Foundation
import Security
let keyChainQuery: NSDictionary = [
kSecClass: <아이템 클래스>,
kSecAttrService: <서비스 아이디>,
kSecAttrAccount: <사용자 계정>,
kSecValueData: <저장할 값>
]
//기존에 저장된 값 삭제해주기
SecItemDelete(keyChainQuery)
//새로운 값 추가
SecItemAdd(keyChainQuery, nil)