Đối với các dữ liệu của app được lưu trong Keychain, khi người dùng xóa app thì các dữ liệu này vẫn sẽ được Keychain giữ lại. Mình không rõ lắm về tác dụng của việc này, nhưng dưới góc nhìn của mình thì việc này không hay ho lắm.
Giả sử bạn lưu tài khoản mật khẩu của user Tèo (và tất cả các user khác) trong Keychain. Sau khi Tèo đăng nhập, sử dụng app của bạn 1 thời gian thì Tèo gặp khó khăn về tài chính và có nhu cầu bán điện thoại, Tèo xoá app của bạn khỏi máy và nghĩ rằng dữ liệu của app (bao gồm cả tài khoản mật khẩu) sẽ bị xoá, vì thực ra thì ai phôn của Tèo cũng hiện lên thông báo này (giả sử app của bạn là Hello 😀 )
Nhưng mọi chuyện không như Tèo nghĩ, tài khoản mật khẩu của Tèo lưu trong máy (trong Keychain) vẫn còn, Tèo đã bán luôn tài khoản mật khẩu của mình với giá … 0đ.
Bạn có thể đã nghe rằng data được lưu trong Keychain được mã hoá rất an toàn, app A không thể truy cập được data được lưu của app B, người dùng cầm điện thoại bấm bấm cũng không xem được data này. Nhưng điều này chỉ đúng với thiết bị chưa jailbreak, với các thiết bị đã jailbreak rồi thì việc dump data từ Keychain khá đơn giản, data được dump ra là data được giải mã luôn.
Hãy xem xét ví dụ sau, mình có một app có chức năng lưu mật khẩu vào Keychain, khi mở app sẽ lấy mật khẩu từ Keychain và hiện mật khẩu này lên
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 |
import SwiftUI import Security struct ContentView: View { @State private var labelText = "" @State private var password = "" @State private var buttonText = "Store password" func storePassword() { guard !password.isEmpty else { print("Password is empty") return } let query = [ kSecClass: kSecClassGenericPassword, kSecAttrAccount: "password", kSecValueData: password.data(using: .utf8)!, ] as CFDictionary let updateFields = [ kSecValueData: password.data(using: .utf8)! ] as CFDictionary let status = SecItemUpdate(query, updateFields) if status == errSecSuccess { buttonText = "Password is stored" } else { SecItemAdd(query, nil) } } func loadPassword() { let query = [ kSecClass: kSecClassGenericPassword, kSecAttrAccount: "password", kSecReturnData: kCFBooleanTrue!, kSecMatchLimit: kSecMatchLimitOne ] as CFDictionary var item: CFTypeRef? let status = SecItemCopyMatching(query, &item) if status == errSecSuccess, let data = item as? Data { if let loadedPassword = String(data: data, encoding: .utf8) { labelText = "Your password from Keychain is: \(loadedPassword)" } } else { labelText = "Password not found in Keychain" } } var body: some View { VStack { Text(labelText) TextField("Enter password", text: $password) .textFieldStyle(RoundedBorderTextFieldStyle()) .padding() .onChange(of: password) { newValue in } Button(action: { storePassword() }, label: { Text(buttonText) }) .padding() .background(Color.blue) .foregroundColor(.white) .cornerRadius(8) } .padding() .onAppear() { loadPassword() } } } struct ContentView_Previews: PreviewProvider { static var previews: some View { ContentView() } } |
Bạn có thể lấy code về chạy thử nhé 😉
Dưới là link video mình chạy thử. Các bước là set password -> xoá app -> cài lại app
Keychain_POC
Như trong video có thể thấy, sau khi xoá app, cài lại thì mật khẩu trước đó đã hiển thị, chứng tỏ sau khi xoá app, data trong Keychain không bị xoá. Theo tìm hiểu của mình thì ở bản ios 10.3 beta, apple đã có tính năng xoá data trong Keychain khi người dùng xoá app, nhưng tính năng này đã bị loại bỏ, cũng không hiểu tại sao, bạn nào biết thì comment cho mình biết với nhá <3
Vậy, với người dùng, khi bán máy bạn nên thực hiện factory reset máy (khôi phục cài đặt gốc) để đảm bảo an toàn hơn, nếu app có chức năng xoá data trong Keychain rồi thì cũng không sao, nhưng cứ làm cho chắc ăn
Với dev, nên tạo một key ngẫu nhiên để mã hoá dữ liệu sau đó lưu key này vào keychain, dữ liệu được mã hoá có thể lưu ở private storage khác như UserDefaults…và xoá dữ liệu nhạy cảm ngay lần đầu người dùng mở app (sau khi cài đặt). Nếu app có chức năng xác thực sinh trắc học, có thể thực hiện lưu key mã hoá vào keychain và set thuộc tính phù hợp để yêu cầu xác thực sinh trắc học mỗi lần lấy key. Với cách triển khai xác thực sinh trắc học đúng đắn, key có thể được bảo vệ ngay cả trên máy đã jailbreak
Với pentester, nên kiểm tra xem app đã xoá data trong các chức năng như logout,.. hay chưa và sau khi xoá app và cài lại thì data trong Keychain còn hay không