Các kỹ thuật khác nhau để bảo mật dữ liệu riêng tư trong iOS Swift. Như chúng ta biết, iOS đã được bảo mật bằng cách cô lập ứng dụng, nơi mà dữ liệu không thể được chuyển từ một ứng dụng sang một ứng dụng khác. Tuy nhiên, nếu bất kỳ kẻ tấn công hoặc xâm nhập nào muốn hack hoặc đánh cắp dữ liệu ngay lập tức, thì việc ngăn chặn họ sẽ trở nên rất khó khăn. Có nhiều phương pháp để bảo mật dữ liệu trong iOS và duy trì tính riêng tư để đạt được mục tiêu này.

Có nhiều cách để bảo vệ dữ liệu trên iOS, vì vậy nhà phát triển cần đảm bảo rằng trong quá trình phát triển ứng dụng iPhone, họ xác định được dữ liệu nào cần được bảo vệ khỏi hacker và sau đó tuân theo các bước tương tự để đảm bảo điều đó. Bảo vệ và bảo mật là quan trọng hơn nhiều trong lĩnh vực ngân hàng so với lĩnh vực khác, vì nếu xảy ra bất kỳ vi phạm nào, thì rất khó để giải quyết tình hình đó.

Kỹ thuật mã hóa và giải mã để bảo mật dữ liệu riêng tư

Kỹ thuật mã hóa thông thường được sử dụng để bảo mật dữ liệu trong iOS khỏi hacker, reverse-engineering, xâm nhập và giả mạo. Mã hóa dữ liệu khi người dùng không truy cập dữ liệu trên thiết bị và giải mã dữ liệu khi người dùng đang truy cập dữ liệu. Kỹ thuật băm được sử dụng ở bất cứ nơi nào cần thiết để bảo mật dữ liệu hàng ngàycủa ứng dụng web/mobile. Bằng cách sử dụng kỹ thuật mã hóa, dữ liệu có thể được mã hóa và chuyển đổi thành định dạng mã hóa, sau đó bằng cách sử dụng kỹ thuật giải mã, dữ liệu có thể được chuyển đổi lại thành văn bản thuần túy. Nhà phát triển cần thêm thư viện mã hóa và viết mã để thực hiện chuyển đổi mã hóa và giải mã.


protocol Cryptographic {
    func encryption(_ string: String) throws -> Data
    func decryptionTech(_ data: Data) throws -> String
}

struct AESHashing {
    private let key: Data
    private let ivSize: Int = kCCBlockSizeAES128 // Kích thước của vector khởi tạo (IV) là 128 bit
    private let options: CCOptions = CCOptions(kCCOptionPKCS7Padding) // Sử dụng padding theo chuẩn PKCS#7
    init(keyString: String) throws {
        // Kiểm tra độ dài của khóa phải là 256 bit (32 bytes)
        guard keyString.count == kCCKeySizeAES256 else {
            throw Error.invalidKeySize
        }
        // Chuyển đổi khóa từ dạng chuỗi sang dạng dữ liệu (Data)
        self.key = Data(keyString.utf8)
    }
}

extension AESHashing {
    // Liệt kê các loại lỗi có thể xảy ra
    enum Error: Swift.Error {
        case invalidKeySize
        case generateRandomIVFailed
        case encryptionFailed
        case decryptionFailed
        case dataToStringFailed
    }
}

private extension AESHashing {
    // Phương thức riêng tư để tạo vector khởi tạo ngẫu nhiên
    func generateRandomIV(for data: inout Data) throws {
        try data.withUnsafeMutableBytes { dataBytes in
            guard let dataBytesBaseAddress = dataBytes.baseAddress else {
                throw Error.generateRandomIVFailed
            }
            // Tạo vector khởi tạo ngẫu nhiên
            let status: Int32 = SecRandomCopyBytes(
                kSecRandomDefault,
                kCCBlockSizeAES128,
                dataBytesBaseAddress
            )
            guard status == 0 else {
                throw Error.generateRandomIVFailed
            }
        }
    }
}

extension AESHashing: Cryptographic {
    // Phương thức để mã hóa dữ liệu
    func encrypt(_ string: String) throws -> Data {
        let dataToEncrypt = Data(string.utf8)
        let bufferSize: Int = ivSize + dataToEncrypt.count + kCCBlockSizeAES128
        var buffer = Data(count: bufferSize)
        // Tạo vector khởi tạo ngẫu nhiên và thêm vào đầu dữ liệu
        try generateRandomIV(for: &buffer)
        var numberBytesEncrypted: Int = 0
        do {
            try key.withUnsafeBytes { keyBytes in
                try dataToEncrypt.withUnsafeBytes { dataToEncryptBytes in
                    try buffer.withUnsafeMutableBytes { bufferBytes in
                        guard let keyBytesBaseAddress = keyBytes.baseAddress,
                              let dataToEncryptBytesBaseAddress = dataToEncryptBytes.baseAddress,
                              let bufferBytesBaseAddress = bufferBytes.baseAddress else {
                            throw Error.encryptionFailed
                        }
                        // Sử dụng thuật toán AES để mã hóa dữ liệu
                        let cryptStatus: CCCryptorStatus = CCCrypt(
                            CCOperation(kCCEncrypt),
                            CCAlgorithm(kCCAlgorithmAES),
                            options,
                            keyBytesBaseAddress,
                            key.count,
                            bufferBytesBaseAddress,
                            dataToEncryptBytesBaseAddress,
                            dataToEncryptBytes.count,
                            bufferBytesBaseAddress + ivSize,
                            bufferSize,
                            &numberBytesEncrypted
                        )
                        guard cryptStatus == CCCryptorStatus(kCCSuccess) else {
                            throw Error.encryptionFailed
                        }
                    }
                }
            }
        } catch {
            throw Error.encryptionFailed
        }
        // Trả về dữ liệu đã được mã hóa
        let encryptedData: Data = buffer[..<(numberBytesEncrypted + ivSize)]
        return encryptedData
    }
    
    // Phương thức để giải mã dữ liệu
    func decryptionTech(_ data: Data) throws -> String {
        let bufferSize: Int = data.count - ivSize
        var buffer = Data(count: bufferSize)
        var numberBytesDecrypted: Int = 0
        do {
            try key.withUnsafeBytes { keyBytes in
                try data.withUnsafeBytes { dataToDecryptBytes in
                    try buffer.withUnsafeMutableBytes { bufferBytes in
                        guard let keyBytesBaseAddress = keyBytes.baseAddress,
                              let dataToDecryptBytesBaseAddress = dataToDecryptBytes.baseAddress,
                              let bufferBytesBaseAddress = bufferBytes.baseAddress else {
                            throw Error.encryptionFailed
                        }
                        // Sử dụng thuật toán AES để giải mã dữ liệu
                        let cryptStatus: CCCryptorStatus = CCCrypt(
                            CCOperation(kCCDecrypt),
                            CCAlgorithm(kCCAlgorithmAES128),
                            options,
                            keyBytesBaseAddress,
                            key.count,
                            dataToDecryptBytesBaseAddress,
                            dataToDecryptBytesBaseAddress + ivSize,
                            bufferSize,
                            bufferBytesBaseAddress,
                            bufferSize,
                            &numberBytesDecrypted
                        )
                        guard cryptStatus == CCCryptorStatus(kCCSuccess) else {
                            throw Error.decryptionFailed
                        }
                    }
                }
            }
        } catch {
            throw Error.encryptionFailed
        }
        // Trích xuất dữ liệu đã giải mã và chuyển đổi sang chuỗi
        let decryptedData: Data = buffer[..]
        guard let decryptedString = String(data: decryptedData, encoding: .utf8) else {
            throw Error.dataToStringFailed
        }
        return decryptedString
    }
}

// Thực hiện mã hóa và giải mã dữ liệu
do {
    let aes = try AESHashing(keyString: "KighsteADhJKiutReatswnhgGJjLOpPnBvCx")
    let stringToEncrypt: String = "Encrypt data"
    print("String to encrypt:\t\t\t\(stringToEncrypt)")
    let encryptedData: Data = try aes.encrypt(stringToEncrypt)
    print("String encrypted (base64):\t\(encryptedData.base64EncodedString())")
    let decryptedData: String = try aes.decryptionTech(encryptedData)
    print("String decrypted:\t\t\t\(decryptedData)")
} catch {
    print("Something went wrong: \(error)")
}


KeyChain là cách khác để bảo vệ dữ liệu bí mật

KeyChain được sử dụng để bảo vệ một số dữ liệu bí mật giới hạn trong ứng dụng. Theo mặc định, KeyChain được mã hóa khi thiết bị bị khóa và khi người dùng mở khóa thiết bị thì keychain sẽ được truy cập. Keychain không được truy cập từ một ứng dụng sang một ứng dụng khác trong thiết bị và apple luôn khuyến nghị sử dụng các tính năng mặc định này cho ứng dụng.

let saveKeychain: Bool = KeychainWrapper.standard.set("Storing Value", forKey: "Storing Key")
let retrievedKeychain: String? = customKeychainWrapperInstance.string(forKey: "Storing Key")
let removeKeychain: Bool = customKeychainWrapperInstance.removeObject(forKey: "Storing Key")

Bảo mật SSL pinning và Bảo vệ dữ liệu từ Hacker

SSL pinning được sử dụng để bảo vệ khỏi hacker, người xâm nhập hoặc reverse-engineering khi mạng được kết nối không dây. SSL pinning được sử dụng để luôn tin tưởng vào máy chủ đúng và nếu bất kỳ máy chủ nào khác cố gắng kết nối hệ thống thì nó sẽ không được kết nối vì lý do bảo mật của SSL pinning. Vì vậy, nhà phát triển cần triển khai logic SSL pinning để bảo vệ ứng dụng khỏi các cuộc tấn công từ bên thứ ba hoặc kẻ xâm nhập.

Cài đặt SSL nên được thực hiện bởi front-end nơi nhà phát triển có thể thêm chứng chỉ cục bộ vào ứng dụng. Nó sẽ khớp với tên miền và chứng chỉ máy chủ. Một khi nó được tin tưởng từ máy chủ với chứng chỉ SSL thì người dùng có thể truy cập ứng dụng nếu không nó sẽ chặn người dùng tại một thời điểm cụ thể. Nhà phát triển cần tạo phiên URL nơi nó có thể chấp nhận hoặc từ chối chứng chỉ từ máy chủ.

fun urlSession1(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
    guard
        challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust,
        let serverTrust = challenge.protectionSpace.serverTrust,
        SecTrustEvaluate(serverTrust, nil) == errSecSuccess,
        let serverCert = SecTrustGetCertificateAtIndex(serverTrust, 0) else {
rejectCertificate (with: completionHandler)
            return
    }
    let serverCertData = SecCertificateCopyData(serverCert) as Data
    guard
        let localCertPath = Bundle.main.path(forResource: "google.com", ofType: "cer"),
        let localCertData = NSData(contentsOfFile: localCertPath) as Data?,
        localCertData == serverCertData else {
            rejectCertificate(with: completionHandler)
            return
    }
    acceptCertificate(with: serverTrust, completionHandler)
}
func rejectCertificate(with completionHandler: ((URLSession.AuthChallengeDisposition, URLCredential?) -> Void)) {
    completionHandler(.cancelAuthenticationChallenge, nil)
}
func acceptCertificate(with serverTrust: SecTrust, _ completionHandler: ((URLSession.AuthChallengeDisposition, URLCredential?) -> Void)) {
    completionHandler(.useCredential, URLCredential(trust: serverTrust))

Nguồn tham khảo : Various Techniques to secure Private data in iOS swift