การจัดเก็บข้อมูลลับใน Keychain
บันทึกและเรียกข้อมูลข้อมูลประจำตัวอย่างปลอดภัย
การจัดเก็บข้อมูลลับใน Keychain เป็นบทเรียน Swift Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 1 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน Swift Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส Swift Academy มีบทเรียนทั้งหมด 4 บทเรียน
เหตุผลที่ใช้พวงกุญแจ
รหัสผ่าน โทเค็น และคีย์ต้องไม่เก็บไว้ใน UserDefaults หรือไฟล์ธรรมดา เพราะอ่านได้ง่าย พวงกุญแจคือฐานข้อมูลลับขนาดเล็กที่เข้ารหัสและจัดการโดย OS ปกป้องด้วยฮาร์ดแวร์และรหัสผ่านของผู้ใช้ นี่เป็นสถานที่ที่ถูกต้องเพียงแห่งเดียวสำหรับข้อมูลรับรอง
import Security
// Keychain stores secrets encrypted at rest,
// survives app updates, and gates access by policy.รายการคือพจนานุกรม
API ของบริการพวงกุญแจใช้ภาษา C: คุณอธิบายรายการด้วยพจนานุกรมคำขอ [String: Any] โดยใช้คีย์ค่าคงที่ kSec... รูปแบบพจนานุกรมเดียวกันนี้ใช้ซ้ำสำหรับการเพิ่ม การค้นหา การอัปเดต และการลบ
import Security
let query: [String: Any] = [
kSecClass as String: kSecClassGenericPassword,
kSecAttrAccount as String: "user@example.com",
kSecAttrService as String: "com.example.app"
]
_ = queryประเภทของรายการ
คีย์ kSecClass ใช้เลือกประเภทของรายการ kSecClassGenericPassword ครอบคลุมโทเค็นและข้อมูลลับของแอป ส่วน kSecClassInternetPassword ใช้เก็บข้อมูลรับรองของเซิร์ฟเวอร์พร้อมแอตทริบิวต์ของโฮสต์และโพรโทคอล ข้อมูลลับของแอปส่วนใหญ่ใช้รหัสผ่านทั่วไป
import Security
// kSecClassGenericPassword -> tokens, API keys
// kSecClassInternetPassword -> server logins
// kSecClassKey / Certificate -> crypto material
let cls = kSecClassGenericPassword
_ = clsการเพิ่มรายการ
SecItemAdd จะแทรกรายการใหม่ คุณต้องใส่ข้อมูลภายใต้ kSecValueData ในรูปแบบ Data พร้อมแอตทริบิวต์ที่ใช้ระบุรายการ เมธอดนี้ส่งคืนค่า OSStatus โดย errSecSuccess หมายถึงดำเนินการสำเร็จ
import Security
func save(_ token: String, account: String) -> Bool {
let query: [String: Any] = [
kSecClass as String: kSecClassGenericPassword,
kSecAttrAccount as String: account,
kSecValueData as String: Data(token.utf8)
]
return SecItemAdd(query as CFDictionary, nil)
== errSecSuccess
}การจัดการรายการซ้ำ
การเพิ่มรายการที่มีแอตทริบิวต์สำหรับระบุรายการซ้ำกับของเดิม จะส่งคืนค่า errSecDuplicateItem การบันทึกที่รับมือได้ดีจะลองใช้ SecItemAdd และหากพบรายการซ้ำ จะใช้ SecItemUpdate เป็นทางเลือก ซึ่งเป็นรูปแบบ upsert
import Security
func upsert(_ data: Data, account: String) -> Bool {
let base: [String: Any] = [
kSecClass as String: kSecClassGenericPassword,
kSecAttrAccount as String: account]
var add = base
add[kSecValueData as String] = data
let status = SecItemAdd(add as CFDictionary, nil)
if status == errSecDuplicateItem {
return SecItemUpdate(base as CFDictionary,
[kSecValueData as String: data] as CFDictionary)
== errSecSuccess
}
return status == errSecSuccess
}การอ่านรายการกลับมา
SecItemCopyMatching ใช้ค้นหา หากต้องการรับไบต์ของข้อมูลลับ คุณต้องตั้งค่า kSecReturnData เป็น true และตั้งค่า kSecMatchLimit เป็น kSecMatchLimitOne ผลลัพธ์จะถูกส่งกลับผ่านพารามิเตอร์ผลลัพธ์เป็น CFTypeRef
import Security
func load(account: String) -> Data? {
let query: [String: Any] = [
kSecClass as String: kSecClassGenericPassword,
kSecAttrAccount as String: account,
kSecReturnData as String: true,
kSecMatchLimit as String: kSecMatchLimitOne]
var result: CFTypeRef?
let status = SecItemCopyMatching(
query as CFDictionary, &result)
guard status == errSecSuccess else { return nil }
return result as? Data
}การอัปเดตรายการ
SecItemUpdate รับพจนานุกรมสองชุด ได้แก่ คิวรีที่ใช้ค้นหารายการ และพจนานุกรมแอตทริบิวต์ที่ต้องการอัปเดต เฉพาะแอตทริบิวต์ที่คุณระบุเท่านั้นที่จะเปลี่ยนแปลง ส่วนอื่นจะคงเดิม
import Security
func update(_ newData: Data, account: String) -> Bool {
let query: [String: Any] = [
kSecClass as String: kSecClassGenericPassword,
kSecAttrAccount as String: account]
let attrs: [String: Any] = [
kSecValueData as String: newData]
return SecItemUpdate(query as CFDictionary,
attrs as CFDictionary) == errSecSuccess
}การลบรายการ
SecItemDelete ลบรายการที่ตรงกัน หากลบสิ่งที่ไม่มีอยู่ ระบบจะส่งคืน errSecItemNotFound ซึ่งคุณสามารถถือว่าเป็นความสำเร็จได้เมื่อกำลังล้างข้อมูลรับรองระหว่างออกจากระบบ
import Security
func delete(account: String) -> Bool {
let query: [String: Any] = [
kSecClass as String: kSecClassGenericPassword,
kSecAttrAccount as String: account]
let status = SecItemDelete(query as CFDictionary)
return status == errSecSuccess
|| status == errSecItemNotFound
}การถอดรหัส OSStatus
ข้อผิดพลาดจะแสดงเป็นรหัสจำนวนเต็มของ OSStatus ส่วน SecCopyErrorMessageString จะแปลงรหัสหนึ่งรายการให้เป็นคำอธิบายที่มนุษย์อ่านเข้าใจได้ ซึ่งมีประโยชน์อย่างยิ่งเมื่อตรวจแก้ปัญหาว่าเหตุใดการบันทึกหรือการอ่านจึงล้มเหลว
import Security
func describe(_ status: OSStatus) -> String {
return SecCopyErrorMessageString(status, nil)
as String? ?? "OSStatus \(status)"
}การระบุรายการให้ไม่ซ้ำกัน
ระบบจับคู่รายการจากการรวมกันของแอตทริบิวต์ โดยทั่วไปคือ kSecAttrService ร่วมกับ kSecAttrAccount สำหรับรหัสผ่านทั่วไป โปรดเลือกสตริง service ที่คงที่และเฉพาะสำหรับแอป เพื่อไม่ให้ข้อมูลลับต่างกันชนกัน
import Security
// Uniqueness for generic passwords usually comes from:
// service (your bundle id) + account (the username)
let service = "com.example.app.auth"
let account = "current-user"
_ = (service, account)ตัวห่อหุ้มขนาดเล็ก
เนื่องจาก API แบบดิบมีรายละเอียดมาก ทีมต่าง ๆ จึงมักห่อหุ้มไว้ในชนิดข้อมูลขนาดเล็กที่เปิดให้ใช้ save, read และ delete วิธีนี้ทำให้ขั้นตอนของ kSec อยู่รวมกันในที่เดียว และจุดเรียกใช้งานดูสะอาดตา
import Security
struct TokenStore {
let service = "com.example.app.auth"
func read(_ account: String) -> Data? {
let q: [String: Any] = [
kSecClass as String: kSecClassGenericPassword,
kSecAttrService as String: service,
kSecAttrAccount as String: account,
kSecReturnData as String: true,
kSecMatchLimit as String: kSecMatchLimitOne]
var out: CFTypeRef?
return SecItemCopyMatching(q as CFDictionary, &out)
== errSecSuccess ? out as? Data : nil
}
}ตรวจสอบความเข้าใจ
ทบทวนวิธีที่ถูกต้องในการดึงไบต์ของข้อมูลลับที่จัดเก็บไว้
สรุปทบทวน
คุณได้เรียนรู้การสร้าง อ่าน แก้ไข และลบข้อมูลในพวงกุญแจ:
- เก็บข้อมูลรับรองไว้ในพวงกุญแจที่เข้ารหัส อย่าเก็บไว้ใน UserDefaults หรือไฟล์
- อธิบายรายการด้วยพจนานุกรมคิวรีของ
kSecและเลือกคลาส เช่นkSecClassGenericPassword SecItemAdd/SecItemCopyMatching/SecItemUpdate/SecItemDeleteครอบคลุมวงจรการใช้งาน ให้จัดการerrSecDuplicateItemด้วยการเพิ่มรายการใหม่หรืออัปเดตรายการเดิม- ระบุรายการด้วย service + account และถอดรหัส
OSStatusเพื่อช่วยตรวจแก้ปัญหา
คำถามที่พบบ่อย
บทเรียน “การจัดเก็บข้อมูลลับใน Keychain” ฟรีหรือไม่
ใช่ — ข้อความเต็มของ “การจัดเก็บข้อมูลลับใน Keychain” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส Swift Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส Swift Academy มีบทเรียนทั้งหมด 4 บทเรียน
คุณจะเรียนรู้อะไรในบทเรียน “การจัดเก็บข้อมูลลับใน Keychain”
บันทึกและเรียกข้อมูลข้อมูลประจำตัวอย่างปลอดภัย คุณปฏิบัติ Swift Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน
คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน Swift Academy หรือไม่
ไม่จำเป็นต้องมีประสบการณ์มาก่อน Swift Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 1 จากทั้งหมด 4 บทเรียน
บทเรียน “การจัดเก็บข้อมูลลับใน Keychain” ใช้เวลานานแค่ไหน
บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย
ฉันเขียนและรันโค้ดในบทเรียน Swift Academy นี้ได้ไหม
ได้ บทเรียน Swift Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- การจัดเก็บข้อมูลลับใน Keychain
- การควบคุมการเข้าถึง Keychain
- การยืนยันตัวตนด้วยข้อมูลชีวมิติ
- การปกป้องข้อมูลและการเข้ารหัส