[swift] SwiftGen과 함께 사용하는 앱 보안 기능

앱 개발 과정에서 보안은 항상 중요한 고려 요소입니다. 악의적인 사용자로부터 유저의 개인정보와 기타 민감한 데이터를 보호하기 위해서는 적절한 보안 기능을 구현해야 합니다. 이번 글에서는 SwiftGen과 함께 사용할 수 있는 몇 가지 보안 기능을 소개하겠습니다.

1. 보안 토큰 관리

앱 내에서 서드파티 API와 통신하거나, 서버에 접근해야 하는 경우가 많습니다. 이때 API 토큰이나 서버와의 연결을 위한 토큰과 같은 보안 키 값을 안전하게 관리해야 합니다. SwiftGen에서 제공하는 키 관리 기능을 사용하면 이를 쉽게 할 수 있습니다.

보안 토큰을 파일로 저장하고자 하는 경우, security 디렉토리를 만들어 그 안에 파일을 저장합니다. 예를 들어, APIKeys.swift라는 파일에 API 키 값을 저장할 수 있습니다.

struct APIKeys {
    static let apiKey = "YOUR_API_KEY"
}

SwiftGen을 사용하여 이 파일을 통해 키 값을 쉽게 접근할 수 있습니다.

import Foundation
import Security

let keychainServiceName = Bundle.main.bundleIdentifier!

if let apiKey = Keychain.get(key: "apiKey", serviceName: keychainServiceName) {
    // API 키 값을 사용하여 통신
} else {
    // 키가 없는 경우, 사용자에게 다시 로그인하라는 메시지를 보여줌
}

2. SSL 인증서 핀단

SSL 인증서 핀단은 중간자 공격을 방지하기 위해 서버의 인증서를 검증하는 기술입니다. 일반적으로 앱은 서버로부터 받은 인증서의 일부 값을 미리 저장해두고, 이를 사용하여 서버의 신뢰성을 검증합니다.

SwiftGen에서 SSL 인증서 핀단을 설정하는 방법은 다음과 같습니다.

class URLSessionDelegate: NSObject, URLSessionDelegate {
    // 서버의 공개키를 미리 저장
    let serverPublicKeyHash = "YOUR_SERVER_PUBLIC_KEY_HASH"

    // 인증서 검증
    func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
        guard let serverTrust = challenge.protectionSpace.serverTrust else {
            completionHandler(.cancelAuthenticationChallenge, nil)
            return
        }
        
        SecTrustEvaluateAsyncWithError(serverTrust, DispatchQueue.main) { (trust, result, error) in
            if let trust = trust, let publicKey = SecTrustCopyPublicKey(trust), let publicKeyHash = publicKey.getPublicKeyHash() {
                if publicKeyHash == self.serverPublicKeyHash {
                    completionHandler(.useCredential, URLCredential(trust: serverTrust))
                } else {
                    completionHandler(.cancelAuthenticationChallenge, nil)
                }
            } else {
                completionHandler(.cancelAuthenticationChallenge, nil)
            }
        }
    }
}

위와 같이 URLSessionDelegate를 구현하고, 인증서의 공개키 값을 미리 저장한 후, 인증서 검증 로직을 수행합니다.

3. 데이터 암호화

앱 내에서 전송되는 데이터를 암호화하여 보안성을 높일 수 있습니다. SwiftGen을 사용하여 데이터를 암호화하고, 복호화하는 기능을 구현할 수 있습니다.

import CryptoKit

extension String {
    func encryptUsingAES(key: SymmetricKey) throws -> String {
        let data = Data(self.utf8)
        let encryptedData = try AES.GCM.seal(data, using: key).combined
        return encryptedData.base64EncodedString()
    }

    func decryptUsingAES(key: SymmetricKey) throws -> String {
        guard let data = Data(base64Encoded: self) else {
            throw EncryptionError.invalidData
        }
        let sealedBox = try AES.GCM.SealedBox(combined: data)
        let decryptedData = try AES.GCM.open(sealedBox, using: key)
        return String(data: decryptedData, encoding: .utf8) ?? ""
    }
}

enum EncryptionError: Error {
    case invalidData
}

위와 같이 String 타입의 확장을 통해 데이터 암호화와 복호화 기능을 추가할 수 있습니다. AES 암호화 알고리즘을 사용하고 있으며, SymmetricKey를 이용하여 암호화 키를 관리합니다.

마무리

SwiftGen을 활용하여 앱 보안 기능을 강화할 수 있습니다. 위에서 소개한 토큰 관리, SSL 인증서 핀단, 데이터 암호화는 앱의 보안성을 높이는데 도움을 줄 수 있는 기능들입니다. 앱의 보안을 유지하고 사용자의 개인정보를 보호하기 위해 이러한 기능들을 적극적으로 활용해보는 것을 추천합니다.

참고 자료