โปรแกรมตรวจสอบคีย์สำหรับ Android ช่วยให้ผู้ใช้มีวิธีที่ปลอดภัยและเป็นหนึ่งเดียวในการ ยืนยันว่าตนกำลังสื่อสารกับบุคคลที่ถูกต้องในแอปที่เข้ารหัสจากต้นทางถึงปลายทาง (E2EE) ของคุณ โดยจะปกป้องผู้ใช้จากการโจมตีแบบ Man-in-the-Middle ด้วยการ อนุญาตให้ผู้ใช้ยืนยันความถูกต้องของคีย์การเข้ารหัสสาธารณะของรายชื่อติดต่อ ผ่าน UI ของระบบที่เชื่อถือได้และสอดคล้องกัน
ฟีเจอร์นี้ให้บริการโดยโปรแกรมตรวจสอบคีย์ ซึ่งเป็นบริการของระบบที่เป็นส่วนหนึ่ง ของบริการของระบบ Google และจัดจำหน่ายโดยใช้ Play Store โดยทำหน้าที่เป็นที่เก็บคีย์สาธารณะ E2EE แบบรวมศูนย์ในอุปกรณ์
เหตุผลที่ควรผสานรวมกับโปรแกรมตรวจสอบคีย์
- มอบ UX ที่เป็นหนึ่งเดียวกัน: คุณสามารถเปิดตัว UI มาตรฐานของระบบแทนการสร้างขั้นตอนการยืนยันของคุณเอง ซึ่งจะช่วยให้ผู้ใช้ได้รับประสบการณ์ที่สอดคล้องกันและเชื่อถือได้ในแอปทั้งหมด
- เพิ่มความมั่นใจให้ผู้ใช้: สถานะการยืนยันที่ชัดเจนและได้รับการสนับสนุนจากระบบจะช่วยให้ผู้ใช้มั่นใจว่าการสนทนาของตนปลอดภัยและเป็นส่วนตัว
- ลดค่าใช้จ่ายในการพัฒนา: ลดความซับซ้อนของ UI การยืนยันคีย์ ที่เก็บข้อมูล และการจัดการสถานะไปยังบริการของระบบ
คำสำคัญ
- lookupKey: ตัวระบุแบบทึบถาวรสำหรับรายชื่อติดต่อ ซึ่งจัดเก็บไว้ในคอลัมน์ LOOKUP_KEY ของผู้ให้บริการรายชื่อติดต่อ
contact ID
ต่างจากlookupKey
ตรงที่ยังคงมีเสถียรภาพแม้ว่าจะมีการเปลี่ยนแปลงหรือผสานรายละเอียดการติดต่อพื้นฐาน ก็ตาม จึงเป็นวิธีที่แนะนำในการอ้างอิงรายชื่อติดต่อ - accountId: ตัวระบุเฉพาะแอปสำหรับบัญชีของผู้ใช้ในอุปกรณ์ รหัสนี้กำหนดโดยแอปของคุณและช่วยแยกความแตกต่างระหว่างบัญชีหลายบัญชี ที่ผู้ใช้รายเดียวอาจมี ซึ่งจะแสดงต่อผู้ใช้ใน UI ดังนั้นเราขอแนะนำให้ใช้ข้อมูลที่มีความหมาย เช่น หมายเลขโทรศัพท์ อีเมล หรือแฮนเดิลของผู้ใช้
- deviceId: ตัวระบุที่ไม่ซ้ำกันสำหรับอุปกรณ์ที่เฉพาะเจาะจงซึ่งเชื่อมโยงกับบัญชีของผู้ใช้ ซึ่งช่วยให้ผู้ใช้มีอุปกรณ์หลายเครื่องได้ โดยแต่ละเครื่องจะมีชุดคีย์การเข้ารหัสของตัวเอง ไม่จำเป็นต้องเป็นอุปกรณ์จริง แต่อาจเป็นวิธีแยกความแตกต่างระหว่างคีย์หลายรายการที่ใช้สำหรับบัญชีเดียวกัน
เริ่มต้นใช้งาน
ก่อนเริ่มต้น ให้ตั้งค่าแอปเพื่อสื่อสารกับบริการ Key Verifier
ประกาศสิทธิ์: ใน AndroidManifest.xml ให้ประกาศสิทธิ์ต่อไปนี้ นอกจากนี้ คุณยังต้องขอสิทธิ์เหล่านี้จากผู้ใช้ในขณะรันไทม์ด้วย
<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.WRITE_CONTACTS" />
รับอินสแตนซ์ไคลเอ็นต์: รับอินสแตนซ์ของ ContactKeys
ซึ่งเป็น
จุดแรกเข้าสู่ API
import com.google.android.gms.contactkeys.ContactKeys
val contactKeyClient = ContactKeys.getClient(context)
คำแนะนำสำหรับนักพัฒนาแอปรับส่งข้อความ
ในฐานะนักพัฒนาแอปรับส่งข้อความ บทบาทหลักของคุณคือการเผยแพร่คีย์สาธารณะของผู้ใช้และคีย์ของรายชื่อติดต่อไปยังบริการตรวจสอบคีย์
เผยแพร่คีย์สาธารณะของผู้ใช้
หากต้องการอนุญาตให้ผู้อื่นค้นหาและยืนยันผู้ใช้ของคุณ ให้เผยแพร่คีย์สาธารณะของผู้ใช้ไปยัง ที่เก็บในอุปกรณ์ พิจารณาสร้างคีย์ใน ที่เก็บคีย์ของ Android เพื่อเพิ่มความปลอดภัย
import com.google.android.gms.contactkeys.ContactKeyClient
import com.google.android.gms.tasks.Tasks
suspend fun publishSelfKey(
contactKeyClient: ContactKeyClient,
accountId: String,
deviceId: String,
publicKey: ByteArray
) {
try {
Tasks.await(
contactKeyClient.updateOrInsertE2eeSelfKey(
deviceId,
accountId,
publicKey
)
)
// Self key published successfully.
} catch (e: Exception) {
// Handle error.
}
}
เชื่อมโยงคีย์สาธารณะกับรายชื่อติดต่อ
เมื่อแอปได้รับคีย์สาธารณะสำหรับรายชื่อติดต่อของผู้ใช้รายใดรายหนึ่ง คุณต้อง จัดเก็บและเชื่อมโยงคีย์ดังกล่าวกับรายชื่อติดต่อนั้นในที่เก็บส่วนกลาง ซึ่งจะ ช่วยให้ยืนยันคีย์ได้และช่วยให้แอปอื่นๆ แสดงสถานะการยืนยัน สำหรับรายชื่อติดต่อได้ หากต้องการดำเนินการนี้ คุณต้องมี lookupKey ของรายชื่อติดต่อจาก ผู้ให้บริการรายชื่อติดต่อของ Android โดยปกติแล้วจะเกิดขึ้นเมื่อดึงข้อมูลคีย์ จากเซิร์ฟเวอร์การกระจายคีย์หรือระหว่างการซิงค์คีย์ในเครื่องเป็นระยะ
import com.google.android.gms.contactkeys.ContactKeyClient
import com.google.android.gms.tasks.Tasks
suspend fun storeContactKey(
contactKeyClient: ContactKeyClient,
contactLookupKey: String,
contactAccountId: String,
contactDeviceId: String,
contactPublicKey: ByteArray
) {
try {
Tasks.await(
contactKeyClient.updateOrInsertE2eeContactKey(
contactLookupKey,
contactDeviceId,
contactAccountId,
contactPublicKey
)
)
// Contact's key stored successfully.
} catch (e: Exception) {
// Handle error.
}
}
เรียกข้อมูลคีย์และสถานะการยืนยัน
หลังจากเผยแพร่คีย์แล้ว ผู้ใช้จะยืนยันคีย์ผ่านการสแกนคิวอาร์โค้ดด้วยตนเองได้ UI ของแอปควรแสดงว่าการสนทนาใช้คีย์ที่ ยืนยันแล้วหรือไม่ คีย์แต่ละรายการมีสถานะการยืนยันที่คุณใช้เพื่อแจ้ง UI ได้
ทำความเข้าใจสถานะการยืนยัน:
UNVERIFIED
: นี่คือสถานะเริ่มต้นของคีย์ใหม่ทุกรายการ ซึ่งหมายความว่าคีย์มีอยู่ แต่ผู้ใช้ยังไม่ได้ยืนยันความถูกต้อง ใน UI คุณ ควรถือว่านี่เป็นสถานะที่เป็นกลางและโดยปกติแล้วจะไม่แสดงตัวบ่งชี้พิเศษ ใดๆVERIFIED
: สถานะนี้บ่งบอกถึงระดับความน่าเชื่อถือสูง ซึ่งหมายความว่าผู้ใช้ ได้ทำขั้นตอนการยืนยัน (เช่น การสแกนคิวอาร์โค้ด) เสร็จสมบูรณ์แล้ว และ ยืนยันว่าคีย์เป็นของผู้ติดต่อที่ต้องการ ใน UI คุณควรแสดงตัวบ่งชี้ที่ชัดเจนและเป็นบวก เช่น เครื่องหมายถูกสีเขียวหรือ โล่VERIFICATION_FAILED
: นี่คือสถานะคำเตือน ซึ่งหมายความว่าคีย์ ที่เชื่อมโยงกับรายชื่อติดต่อไม่ตรงกับคีย์ที่ ยืนยันแล้วก่อนหน้านี้ ซึ่งอาจเกิดขึ้นได้หากรายชื่อติดต่อมีอุปกรณ์ใหม่ แต่อาจบ่งบอกถึงความเสี่ยงด้านความปลอดภัยได้ด้วย ใน UI ให้แจ้งเตือนผู้ใช้ พร้อมคำเตือนที่ชัดเจนและแนะนำให้ผู้ใช้ยืนยันอีกครั้งก่อนส่งข้อมูลที่ละเอียดอ่อน
คุณเรียกดูสถานะรวมของคีย์ทั้งหมดที่เชื่อมโยงกับรายชื่อติดต่อได้ เราขอแนะนำให้ใช้ VerificationState.leastVerifiedFrom()
เพื่อแก้ไขสถานะ
เมื่อมีคีย์หลายรายการ เนื่องจากจะจัดลำดับความสำคัญของ VERIFICATION_FAILED
เหนือ VERIFIED
ได้อย่างถูกต้อง
- การดูสถานะรวมในระดับรายชื่อติดต่อ
import com.google.android.gms.contactkeys.ContactKeyClient
import com.google.android.gms.contactkeys.constants.VerificationState
import com.google.android.gms.tasks.Tasks
suspend fun displayContactVerificationStatus(
contactKeyClient: ContactKeyClient,
contactLookupKey: String
) {
try {
val keysResult = Tasks.await(contactKeyClient.getAllE2eeContactKeys(contactLookupKey))
val states =
keysResult.keys.map { VerificationState.fromState(it.localVerificationState) }
val contactStatus = VerificationState.leastVerifiedFrom(states)
updateUi(contactLookupKey, contactStatus)
} catch (e: Exception) {
// Handle error.
}
}
- การดูสถานะรวมที่ระดับบัญชี
import com.google.android.gms.contactkeys.ContactKeyClient
import com.google.android.gms.contactkeys.constants.VerificationState
import com.google.android.gms.tasks.Tasks
suspend fun displayAccountVerificationStatus(
contactKeyClient: ContactKeyClient,
accountId: String
) {
try {
val keys = Tasks.await(contactKeyClient.getE2eeAccountKeysForAccount(accountId))
val states = keys.map { VerificationState.fromState(it.localVerificationState) }
val accountStatus = VerificationState.leastVerifiedFrom(states)
updateUi(accountId, accountStatus)
} catch (e: Exception) {
// Handle error.
}
}
สังเกตการเปลี่ยนแปลงที่สำคัญแบบเรียลไทม์
คุณควรรับฟังข้อมูลอัปเดตเพื่อให้มั่นใจว่า UI ของแอปจะแสดงสถานะความน่าเชื่อถือที่ถูกต้องเสมอ วิธีที่แนะนำคือการใช้ Flow-based API ซึ่งจะส่งรายการคีย์ใหม่ทุกครั้งที่มีการเพิ่ม นำออก หรือเปลี่ยนสถานะการยืนยันของคีย์สำหรับบัญชีที่สมัครใช้บริการ ซึ่งจะมีประโยชน์อย่างยิ่งในการอัปเดตรายชื่อสมาชิกของการสนทนากลุ่ม ให้เป็นปัจจุบัน สถานะการยืนยันของคีย์อาจเปลี่ยนแปลงได้ในกรณีต่อไปนี้
- ผู้ใช้ทำขั้นตอนการยืนยันเสร็จสมบูรณ์ (เช่น สแกนคิวอาร์โค้ด)
- คีย์ของรายชื่อติดต่อได้รับการแก้ไข ทำให้ไม่ตรงกับค่าที่ยืนยันก่อนหน้านี้อีกต่อไป
fun observeKeyUpdates(contactKeyClient: ContactKeyClient, accountIds: List<String>) {
lifecycleScope.launch {
contactKeyClient.getAccountContactKeysFlow(accountIds)
.collect { updatedKeys ->
// A key was added, removed, or updated.
// Refresh your app's UI and internal state.
refreshUi(updatedKeys)
}
}
}
ดำเนินการยืนยันคีย์ด้วยตนเอง
วิธีที่ปลอดภัยที่สุดสำหรับผู้ใช้ในการยืนยันคีย์คือการยืนยันด้วยตนเอง ซึ่งมักจะทำโดยการสแกนคิวอาร์โค้ดหรือเปรียบเทียบลำดับตัวเลข แอป Key Verifier มีโฟลว์ UI มาตรฐานสำหรับกระบวนการนี้ ซึ่งแอปของคุณสามารถเปิดใช้ได้ หลังจากพยายามยืนยันแล้ว API จะอัปเดตสถานะการยืนยันของคีย์โดยอัตโนมัติ และแอปจะได้รับการแจ้งเตือนหากคุณสังเกตการอัปเดตคีย์
- เริ่มกระบวนการยืนยันคีย์สำหรับรายชื่อติดต่อที่ผู้ใช้เลือก
เปิด
PendingIntent
ที่getScanQrCodeIntent
ให้มาโดยใช้lookupKey
ของรายชื่อติดต่อที่เลือก UI ช่วยให้ผู้ใช้ยืนยันคีย์ทั้งหมด สำหรับรายชื่อติดต่อที่ระบุได้
import android.app.ActivityOptions
import android.app.PendingIntent
import com.google.android.gms.contactkeys.ContactKeyClient
import com.google.android.gms.tasks.Tasks
suspend fun initiateVerification(contactKeyClient: ContactKeyClient, lookupKey: String) {
try {
val pendingIntent = Tasks.await(contactKeyClient.getScanQrCodeIntent(lookupKey))
val options =
ActivityOptions.makeBasic()
.setPendingIntentBackgroundActivityStartMode(
ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED
)
.toBundle()
pendingIntent.send(options)
} catch (e: Exception) {
// Handle error.
}
}
- เริ่มกระบวนการยืนยันคีย์สำหรับบัญชีที่ผู้ใช้เลือก
หากผู้ใช้ต้องการยืนยันบัญชีที่ไม่ได้ลิงก์กับรายชื่อติดต่อโดยตรง
(หรือบัญชีใดบัญชีหนึ่งของรายชื่อติดต่อ) คุณสามารถเปิด
PendingIntent
ที่getScanQrCodeIntentForAccount
ให้ไว้ได้ โดยปกติจะใช้สำหรับชื่อแพ็กเกจและรหัสบัญชีของแอปของคุณเอง
import android.app.ActivityOptions
import android.app.PendingIntent
import com.google.android.gms.contactkeys.ContactKeyClient
import com.google.android.gms.tasks.Tasks
suspend fun initiateVerification(contactKeyClient: ContactKeyClient, packageName: String, accountId: String) {
try {
val pendingIntent = Tasks.await(contactKeyClient.getScanQrCodeIntentForAccount(packageName, accountId))
// Allow activity start from background on Android SDK34+
val options =
ActivityOptions.makeBasic()
.setPendingIntentBackgroundActivityStartMode(
ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED
)
.toBundle()
pendingIntent.send(options)
} catch (e: Exception) {
// Handle error.
}
}