[swift] Swift 보안을 위한 취약한 디자인 패턴 방지

Swift는 안전하고 보안적으로 견고한 언어로 알려져 있습니다. 그러나 개발자가 취약한 디자인 패턴을 사용하면 애플리케이션의 보안에 위협을 가할 수 있습니다. 이러한 취약점을 방지하기 위해 몇 가지 좋은 디자인 패턴과 기술적인 방법을 소개하겠습니다.

1. 비밀 정보 저장

애플리케이션에서 사용되는 비밀 정보는 보안에 매우 중요합니다. 비밀 정보를 저장할 때에는 안전한 방법을 사용해야 합니다. 일반적으로 비밀 정보를 저장하기 위해 Keychain을 사용하는 것이 좋습니다. Keychain은 iOS에서 데이터를 안전하게 저장하고 암호화하는 기능을 제공합니다.

import UIKit
import Security

class KeychainHelper {
    static func savePassword(service: String, account: String, password: String) -> Bool {
        if let data = password.data(using: .utf8) {
            let query: [String: Any] = [
                kSecClass as String: kSecClassGenericPassword,
                kSecAttrService as String: service,
                kSecAttrAccount as String: account,
                kSecValueData as String: data
            ]
            let status = SecItemAdd(query as CFDictionary, nil)
            return status == errSecSuccess
        }
        return false
    }
    
    static func getPassword(service: String, account: String) -> String? {
        let query: [String: Any] = [
            kSecClass as String: kSecClassGenericPassword,
            kSecAttrService as String: service,
            kSecAttrAccount as String: account,
            kSecMatchLimit as String: kSecMatchLimitOne,
            kSecReturnData as String: true
        ]
        var result: AnyObject?
        let status = SecItemCopyMatching(query as CFDictionary, &result)
        if status == errSecSuccess {
            if let data = result as? Data {
                return String(data: data, encoding: .utf8)
            }
        }
        return nil
    }
}

위의 예제는 Keychain에 비밀번호를 저장하고 검색하는 간단한 클래스입니다. savePassword 메서드를 사용하여 비밀번호를 저장하고, getPassword 메서드를 사용하여 저장된 비밀번호를 검색할 수 있습니다. 이렇게 Keychain을 사용하면 비밀 정보를 안전하게 저장할 수 있습니다.

2. 인증 토큰 관리

인증 토큰은 사용자를 인증하고 권한을 부여하는 데 사용됩니다. 앱에서 인증 토큰을 사용할 때 적절한 방법으로 관리해야 합니다. 인증 토큰을 저장할 때에는 메모리에 직접 저장하지 않고, 안전한 저장소에 저장하는 것이 중요합니다.

iOS에서는 UserDefaults를 사용하여 인증 토큰을 저장하는 것이 일반적입니다. UserDefaults는 간단한 key-value 저장소이지만, 사용자의 액세스 권한을 가집니다. 이를 통해 인증 토큰과 같은 중요한 정보를 안전하게 저장할 수 있습니다.

import Foundation

class TokenManager {
    static let shared = TokenManager()
    
    private let tokenKey = "AuthToken"
    
    var authToken: String? {
        get {
            return UserDefaults.standard.string(forKey: tokenKey)
        }
        set {
            UserDefaults.standard.set(newValue, forKey: tokenKey)
        }
    }
    
    private init() {}
}

위의 예제는 TokenManager 클래스입니다. TokenManagerUserDefaults를 사용하여 인증 토큰을 저장하고, 가져올 수 있도록 만들어줍니다. 이렇게 인증 토큰을 안전하게 관리하면 보안상의 문제를 피할 수 있습니다.

3. 외부 입력의 유효성 검사

외부 입력을 사용하는 경우, 해당 입력을 유효성 검사해야 합니다. 예를 들어 사용자로부터 입력 받은 데이터를 서버로 전송하기 전에 유효성을 검사하여 악의적인 코드가 주입되지 않도록 방지할 수 있습니다. Swift에서는 다양한 내장 유효성 검사 함수를 제공합니다.

let input = "1234"
let isValid = isValidNumber(input)

func isValidNumber(_ number: String) -> Bool {
    let numberRegex = "^[0-9]+$"
    let numberPredicate = NSPredicate(format: "SELF MATCHES %@", numberRegex)
    return numberPredicate.evaluate(with: number)
}

위의 예제는 숫자인지 확인하는 isValidNumber 함수입니다. 입력된 문자열이 숫자만으로 구성되어 있는지 확인하는 정규 표현식을 사용하여 유효성을 검사합니다. 이렇게 외부 입력의 유효성을 검사함으로써 보안적인 문제를 방지할 수 있습니다.

결론

Swift 언어는 안전하고 보안적으로 견고한 언어이지만, 취약한 디자인 패턴을 사용할 경우 애플리케이션의 보안에 위협을 가할 수 있습니다. 따라서 비밀 정보 저장, 인증 토큰 관리, 외부 입력의 유효성 검사 등을 신경써야 합니다. 이러한 방법들을 적용하여 Swift 앱의 보안을 강화할 수 있습니다.

참고 자료