Keychain — Khái niệm chính, kiến trúc và cách hoạt động

Tác giả: IT Sectr Đã đăng: 2026-03-14 Thời gian đọc: 10 phút

Keychain là kho lưu trữ thông tin xác thực an toàn trong iOS, watchOS, macOS và tvOS quản lý mật khẩu, khóa và chứng chỉ ở cấp độ phần cứng. Không giống như UserDefaults, dữ liệu trong Keychain được mã hóa và cách ly theo sandbox của ứng dụng. Theo Apple Developer Documentation, Keychain sử dụng cơ chế Secure Enclave và mã hóa phần cứng AES-256 để bảo vệ thông tin nhạy cảm.

Điểm chính

  • Keychain — kho lưu trữ hệ thống iOS cho mật khẩu, khóa và chứng chỉ với mã hóa phần cứng
  • Security framework cung cấp các hàm C SecItemAdd, SecItemCopyMatching và SecItemDelete để làm việc với Keychain
  • Quyền truy cập Keychain bị giới hạn bởi sandbox ứng dụng, nhưng có thể truy cập chia sẻ qua keychain access groups
  • Thuộc tính kSecAttrAccessible xác định mức bảo vệ: từ Always đến WhenUnlockedThisDeviceOnly
  • Keychain hỗ trợ lưu trữ mật khẩu, khóa đối xứng và bất đối xứng, chứng chỉ X.509

Keychain là gì?

Keychain là cơ sở dữ liệu an toàn của hệ điều hành Apple được thiết kế để lưu trữ an toàn mật khẩu, khóa mật mã, chứng chỉ và các dữ liệu nhạy cảm khác. Keychain lần đầu tiên xuất hiện trong Mac OS 8.6 vào năm 1999 và trên iOS — từ phiên bản SDK đầu tiên.

Định nghĩa và mục đích

Keychain giải quyết vấn đề cơ bản của phát triển di động: lưu trữ bí mật (token, mật khẩu, khóa mã hóa) trong hệ thống tệp không an toàn. Không giống như UserDefaults hay SQLite, dữ liệu trong Keychain được lưu trữ dưới dạng mã hóa và tự động mã hóa khi ghi vào đĩa.

Mỗi ứng dụng iOS hoạt động trong một sandbox biệt lập và chỉ có quyền truy cập vào keychain của riêng mình. Tuy nhiên, nhà phát triển có thể cấu hình quyền truy cập Keychain chia sẻ giữa các ứng dụng của cùng một nhà phát triển thông qua keychain access groups. iCloud Keychain của người dùng đồng bộ hóa dữ liệu giữa các thiết bị qua mã hóa đầu cuối.

Theo Apple Security White Paper (2025), Keychain sử dụng mã hóa phần cứng AES-256 với khóa liên kết với định danh thiết bị duy nhất (UID), khiến dữ liệu không thể truy cập khi trích xuất khỏi thiết bị.

Keychain hoạt động thế nào trên iOS?

Keychain hoạt động như một dịch vụ phân lớp: ứng dụng truy cập Security framework, framework này giao tiếp với daemon securityd quản lý cơ sở dữ liệu SQLite mã hóa của Keychain. Mỗi bản ghi được mã hóa bằng một khóa riêng biệt và các khóa tự được bảo vệ bởi mô-đun phần cứng Secure Enclave trên các thiết bị có chip A7 trở lên.

Kiến trúc Security framework

Security framework cung cấp giao diện C để làm việc với Keychain Services. Các hàm chính: SecItemAdd (thêm), SecItemCopyMatching (tìm kiếm), SecItemUpdate (cập nhật) và SecItemDelete (xóa). Mỗi thao tác chấp nhận một từ điển thuộc tính CFDictionaryRef mô tả loại yêu cầu.

Dữ liệu được phân loại theo lớp: kSecClassGenericPassword (mật khẩu tùy ý), kSecClassInternetPassword (mật khẩu dịch vụ Internet), kSecClassCertificate (chứng chỉ), kSecClassKey (khóa mật mã) và kSecClassIdentity (cặp khóa và chứng chỉ).

Quy trình lưu dữ liệu

Khi lưu mật khẩu, ứng dụng tạo một từ điển với các thuộc tính: dịch vụ, tài khoản, mức truy cập, nhãn. Security framework truyền dữ liệu cho daemon securityd, daemon này mã hóa bản ghi bằng khóa liên kết với thiết bị và lưu vào SQLite của Keychain. Việc truy xuất diễn ra tương tự: truy vấn theo thuộc tính, tìm kiếm, giải mã và trả về dữ liệu.

Một đặc điểm quan trọng: khi xóa ứng dụng, iOS tự động xóa các bản ghi Keychain do ứng dụng đó tạo ra (từ iOS 10.3+). Khi cài đặt lại ứng dụng, dữ liệu Keychain từ lần cài đặt trước không khả dụng trừ khi đã sử dụng iCloud Keychain.

swift
import Security

func savePassword(service: String, account: String, password: Data) {
    let query: [String: Any] = [
        kSecClass as String: kSecClassGenericPassword,
        kSecAttrService as String: service,
        kSecAttrAccount as String: account,
        kSecValueData as String: password,
        kSecAttrAccessible as String: kSecAttrAccessibleWhenUnlocked
    ]
    SecItemAdd(query as CFDictionary, nil)
}

Các loại dữ liệu trong Keychain

Keychain hỗ trợ năm lớp dữ liệu chính, mỗi lớp có bộ thuộc tính và phạm vi ứng dụng riêng. Việc chọn lớp xác định khóa tìm kiếm nào có sẵn và dữ liệu được mã hóa như thế nào.

Mật khẩu và tài khoản

Các lớp kSecClassGenericPasswordkSecClassInternetPassword được thiết kế để lưu trữ mật khẩu dạng chuỗi. Phiên bản Internet lưu thêm dữ liệu máy chủ: tên miền, giao thức, cổng và đường dẫn xác thực. GenericPassword được sử dụng để lưu trữ bất kỳ mật khẩu nào không gắn với máy chủ.

Khi lưu mật khẩu Internet, bạn có thể chỉ định kSecAttrServer (tên miền), kSecAttrProtocol (HTTPS, FTP, v.v.), kSecAttrPortkSecAttrPath. Điều này cho phép xác định chính xác bản ghi khi tự động điền qua AutoFill.

Khóa mật mã và chứng chỉ

Lớp kSecClassKey lưu trữ khóa đối xứng (AES) và bất đối xứng (RSA, EC). Lớp kSecClassCertificate lưu trữ chứng chỉ X.509. Lớp kSecClassIdentity kết hợp khóa riêng tư và chứng chỉ tương ứng thành một bản ghi.

Đối với khóa bất đối xứng, Keychain hỗ trợ các thuộc tính: kSecAttrKeyType (RSA, EC), kSecAttrKeySizeInBits (2048, 256), kSecAttrIsPermanent (có lưu vào Keychain không). Đối với chứng chỉ: kSecAttrLabel (tên dễ đọc), kSecAttrSubject (DN chủ sở hữu), kSecAttrIssuer (DN nhà phát hành).

Lớp KeychainMục đíchLoại dữ liệu
kSecClassGenericPasswordMật khẩu ứng dụngData (NSString)
kSecClassInternetPasswordMật khẩu máy chủData + thuộc tính máy chủ
kSecClassCertificateChứng chỉ X.509SecCertificate
kSecClassKeyKhóa mật mãSecKey
kSecClassIdentityKhóa + chứng chỉSecIdentity

Làm việc với Keychain qua API

Giao diện chính để tương tác với Keychain trong mã iOS gốc là các hàm của Security framework. Đối với Swift và Objective-C, một giao diện C duy nhất có sẵn, được bọc trong các hàm tiện lợi.

Thao tác cơ bản SecItemAdd và SecItemCopyMatching

Hàm SecItemAdd thêm một mục mới vào Keychain. Nó nhận đầu vào là một từ điển với lớp, dữ liệu và thuộc tính. Trả về trạng thái errSecSuccess (0) hoặc mã lỗi. Hàm SecItemCopyMatching thực hiện tìm kiếm theo thuộc tính và trả về dữ liệu tìm thấy.

Để tìm kiếm, sử dụng cờ kSecReturnData — nếu true, hàm trả về nội dung của bản ghi. Cờ kSecMatchLimit xác định số lượng kết quả: kSecMatchLimitOne (một) hoặc kSecMatchLimitAll (tất cả).

swift
func readPassword(service: String, account: String) -> Data? {
    let query: [String: Any] = [
        kSecClass as String: kSecClassGenericPassword,
        kSecAttrService as String: service,
        kSecAttrAccount as String: account,
        kSecReturnData as String: true,
        kSecMatchLimit as String: kSecMatchLimitOne
    ]
    var item: CFTypeRef?
    let status = SecItemCopyMatching(query as CFDictionary, &item)
    guard status == errSecSuccess else { return nil }
    return item as? Data
}

Xóa và cập nhật bản ghi

SecItemUpdate cho phép thay đổi thuộc tính hoặc dữ liệu của bản ghi hiện có. SecItemDelete xóa tất cả bản ghi khớp với từ điển được truyền vào. Khi xóa, điều quan trọng là chỉ định đủ thuộc tính để không vô tình xóa bản ghi của ứng dụng khác trong keychain chia sẻ.

swift
func deletePassword(service: String, account: String) {
    let query: [String: Any] = [
        kSecClass as String: kSecClassGenericPassword,
        kSecAttrService as String: service,
        kSecAttrAccount as String: account
    ]
    SecItemDelete(query as CFDictionary)
}

Mức truy cập và bảo vệ dữ liệu

Mỗi bản ghi Keychain có thuộc tính kSecAttrAccessible, xác định thời điểm dữ liệu có sẵn để đọc. Điều này cực kỳ quan trọng cho bảo mật: mức truy cập sai có thể khiến dữ liệu dễ bị tổn thương hoặc ngược lại, không khả dụng khi cần.

Các hằng số khả dụng

kSecAttrAccessibleWhenUnlocked — dữ liệu chỉ khả dụng khi thiết bị được mở khóa. kSecAttrAccessibleAfterFirstUnlock — khả dụng sau lần mở khóa đầu tiên sau khi khởi động lại. kSecAttrAccessibleAlways — luôn khả dụng (không khuyến nghị). Hậu tố ThisDeviceOnly ngăn chặn việc truyền dữ liệu qua sao lưu.

Trên các thiết bị có Secure Enclave, khóa mã hóa của Keychain có thể được bảo vệ thêm bằng sinh trắc học: kSecAccessControlBiometryCurrentSet hoặc kSecAccessControlUserPresence. Điều này thêm yêu cầu Face ID hoặc Touch ID cho mỗi thao tác đọc.

iCloud Keychain và đồng bộ hóa

iCloud Keychain đồng bộ hóa bản ghi giữa các thiết bị Apple qua mã hóa đầu cuối. Apple không có quyền truy cập vào dữ liệu đã giải mã. Để bật đồng bộ hóa, hãy thêm thuộc tính kSecAttrSynchronizable với giá trị kCFBooleanTrue.

Quan trọng: các bản ghi được đồng bộ hóa không thể chứa thuộc tính ThisDeviceOnly vì chúng phải khả dụng trên các thiết bị khác. Nếu mất tất cả thiết bị, iCloud Keychain có thể được khôi phục qua mã khôi phục hoặc khóa khôi phục iCloud.

Thực hành tốt nhất để chọn mức truy cập

Đối với token xác thực, hãy sử dụng kSecAttrAccessibleWhenUnlockedThisDeviceOnly — dữ liệu chỉ khả dụng khi thiết bị được mở khóa và không được sao chép vào bản sao lưu. Đối với chứng chỉ cần khả dụng cho các tác vụ nền, hãy sử dụng kSecAttrAccessibleAfterFirstUnlock. Không bao giờ sử dụng kSecAttrAccessibleAlways cho dữ liệu nhạy cảm.

Khuyến nghị luôn thêm hậu tố ThisDeviceOnly cho dữ liệu không yêu cầu đồng bộ hóa. Điều này ngăn chặn việc sao chép vô tình bí mật vào iCloud hoặc iTunes backup, nơi chúng có thể bị trích xuất bằng các công cụ phân tích. Đối với dữ liệu quan trọng, hãy kết hợp khả dụng với kSecAccessControlUserPresence — điều này thêm yêu cầu sinh trắc học hoặc mã để giải mã bản ghi.

Khi sử dụng iCloud Keychain, hãy lưu ý rằng các bản ghi được đồng bộ hóa khả dụng trên tất cả thiết bị của người dùng: nếu kẻ tấn công truy cập được một thiết bị, dữ liệu có thể bị xâm phạm trên tất cả. Đối với bí mật cô lập, hãy sử dụng ThisDeviceOnly.

Câu hỏi thường gặp

Keychain khác UserDefaults như thế nào?

UserDefaults lưu trữ dữ liệu dưới dạng văn bản thuần túy trong tệp .plist, có thể truy cập khi phân tích IPA. Keychain mã hóa từng bản ghi riêng biệt, sử dụng mã hóa phần cứng và hỗ trợ mức truy cập, sinh trắc học và đồng bộ hóa qua iCloud.

Làm thế nào để xóa Keychain khi kiểm thử?

Mỗi lần khởi chạy trình mô phỏng iOS, Keychain bị xóa. Trên thiết bị thật, hãy xóa ứng dụng — iOS sẽ xóa tất cả bản ghi Keychain của nhà phát triển đó. Để xóa có chọn lọc, hãy gọi SecItemDelete với các thuộc tính thích hợp.

Hai ứng dụng có thể dùng chung Keychain không?

Có, thông qua keychain access groups. Các ứng dụng phải có cùng team ID trong hồ sơ cấp phép và entitlements với cùng keychain-access-groups. Nhà phát triển cấu hình quyền truy cập chia sẻ trong Xcode Capabilities.

Kích thước dữ liệu tối đa trong Keychain là bao nhiêu?

Apple không ghi lại giới hạn nghiêm ngặt, nhưng trong thực tế khuyến nghị không vượt quá 1–4 KB cho mỗi bản ghi. Đối với khối lượng lớn hơn, hãy sử dụng mã hóa tệp và lưu khóa trong Keychain, còn dữ liệu trong Documents.

Keychain có an toàn trên thiết bị jailbreak không?

Trên thiết bị jailbreak, bảo vệ Keychain giảm vì kẻ tấn công có quyền truy cập root và có thể đọc trực tiếp SQLite của Keychain. Đối với dữ liệu quan trọng, hãy sử dụng mã hóa bổ sung với khóa lấy từ máy chủ.

Tổng kết

  • Keychain — kho lưu trữ an toàn iOS cho mật khẩu, khóa và chứng chỉ với mã hóa phần cứng AES-256
  • Security framework cung cấp C-API: SecItemAdd để ghi, SecItemCopyMatching để đọc, SecItemDelete để xóa
  • Lớp dữ liệu Keychain: GenericPassword, InternetPassword, Certificate, Key, Identity — mỗi lớp có bộ thuộc tính riêng
  • kSecAttrAccessible kiểm soát mức truy cập: WhenUnlocked, AfterFirstUnlock, Always, với tùy chọn ThisDeviceOnly
  • iCloud Keychain đồng bộ hóa bản ghi giữa các thiết bị qua mã hóa đầu cuối với thuộc tính kSecAttrSynchronizable
  • Sinh trắc học (Face ID / Touch ID) bảo vệ truy cập Keychain qua kSecAccessControlBiometryCurrentSet
  • Sử dụng Keychain để lưu trữ token OAuth, mật khẩu và khóa mật mã — không lưu bí mật trong UserDefaults

Chúng tôi sẽ phát triển ứng dụng di động chìa khóa trao tay

IT Sectr tạo các ứng dụng iOS và Android cho các công ty khởi nghiệp và doanh nghiệp từ năm 2017. Chúng tôi sẽ tư vấn và đề xuất giải pháp tốt nhất cho bạn.

Thảo luận dự án

Đọc thêm