현재 진행 중인 프로젝트에 Google Books API를 사용하고 있다. 커밋을 하려다 API 키가 하드코딩 되었다는 사실에 부랴부랴 찾아본 API 키에 보안을 적용하는 방법을 정리한다.
우선, 내가 알아본 방법은 아래 세 가지다.
Info.plist에 API 키 저장 후 가져오기
.xcconfig 파일을 사용해 환경 변수로 관리
KeyChain 또는 서버에서 API 키를 받아오기
나는 Info.plist를 사용했지만, 혹시 몰라 위 세 가지 방법에 대해 정리한다.
.xcconfig 파일을 사용하는 방법이 더 안전하다고 판단되어 변경했다.
Info.plist
Xcode - 프로젝트 폴더 - Info.plist 클릭
아래 내용 추가
Key: 식별자(ex.
GOOGLE_BOOKS_API_KEY
)Type:
String
Value:
API Key
API 키를 불러오는 함수 추가
private var apiKey: String { guard let key = Bundle.main.object(forInfoDictionaryKey: "식별자") as? String else { fatalError("Not found API key.") } return key }
.xcconfig
Config.xcconfig 파일 생성 및 설정
Config.xcconfig에
API_KEY = your_debug_api_key
입력
프로젝트에 .xcconfig 연결
Project - Info - Configurations
Debug
와Release
중 원하는 곳에 Config.xcconfig 파일 지정
Info.plist에 환경 변수 추가
Key:
API_KEY
Type:
String
Value:
$(API_KEY)
테스트
print(Bundle.main.object(forInfoDictionaryKey: "API_KEY") as? String ?? "No Key")
Keychain
import Security
func saveAPIKeyToKeychain(apiKey: String) {
let keychainQuery: [String: Any] = [
kSecClass as String: kSecClassGenericPassword,
kSecAttrService as String: "Bundle Identifier",
kSecAttrAccount as String: "식별자",
kSecValueData as String: apiKey.data(using: .utf8)!
]
SecItemAdd(keychainQuery as CFDictionary, nil)
}
func getAPIKeyFromKeychain() -> String? {
let keychainQuery: [String: Any] = [
kSecClass as String: kSecClassGenericPassword,
kSecAttrService as String: "Bundle Identifier",
kSecAttrAccount as String: "식별자",
kSecReturnData as String: kCFBooleanTrue!,
kSecMatchLimit as String: kSecMatchLimitOne
]
var dataTypeRef: AnyObject?
let status = SecItemCopyMatching(keychainQuery as CFDictionary, &dataTypeRef)
if status == errSecSuccess, let retrievedData = dataTypeRef as? Data {
return String(data: retrievedData, encoding: .utf8)
}
return nil
}