device-attestation · L1

設備證明 Level 1:Apple App Attest(註冊一次、每次蓋章)

Chance Lu · 學習文章 · 2026-10-22 15:32
Chance Lu

Level 0 的骨架是:平台在保險箱裡蓋章,伺服器自己驗章。這站看 iPhone 上 Apple 的版本 —— App Attest:讓你的伺服器確認「連進來的,是跑在真 iPhone 上的正版 App」。

一句話:先請 Apple 替一顆章作證(註冊一次),之後每個重要請求都蓋這顆章(每次蓋章)。
① 註冊:裝好 App 後做一次(要連 Apple) Apple 伺服器替這顆章作證 iPhone產生一顆章 你的伺服器驗證明、存下章的樣本 ① 請 Apple 作證 ② 回印鑑證明 ③ 轉交 ② 每次請求:手機自己蓋章(不連 Apple) iPhone用章蓋在請求上 你的伺服器拿樣本比對 請求+章

總覽:上面那段裝好 App 後做一次;下面那段每個重要請求都做(點圖可放大)

四個名詞就夠

名詞白話
章(金鑰)藏在 iPhone 安全晶片(Secure Enclave)裡的私鑰。誰都拿不出來,只能請晶片幫你蓋。App 手上只有它的號碼牌 keyId(其實就是公鑰的指紋)。
attestation(註冊)Apple 開一張「印鑑證明」:這顆章在真的 iPhone、正版 App 裡。裝好 App 後做一次;之後只有重裝、換機、從備份還原才要重做,一般的 App 更新不用。
assertion(蓋章)之後每個重要請求,都用這顆章蓋在「請求內容+challenge」上。
counter(計數器)這顆章總共蓋過幾次。每蓋一次 +1。

(challenge 是 L0 學過的:伺服器發的一次性亂數,用來防止舊資料被重送。
指紋(雜湊、SHA256)=把資料壓成一小段代碼,內容改一個字,指紋就完全不同。)

第一段:註冊(裝好 App 後做一次)

像去戶政事務所辦印鑑證明:Apple 作證,你的伺服器看過證明後,把章的樣本(公鑰)存檔。

Apple 伺服器替金鑰作證 iPhoneApp+Secure Enclave 你的伺服器驗證、存檔 ① generateKey私鑰進 Secure Enclave,拿到 keyId ② 我要一個 challenge ③ challenge(伺服器記下來) ④ 請 Apple 作證:keyId+challenge 指紋 ⑤ 印鑑證明(attestation object) ⑥ 印鑑證明+keyId ⑦ 問五個問題通過才存:公鑰(章的樣本) ⑧ 註冊完成

圖 A:註冊流程。只有第 ④ 步會連到 Apple(點圖可放大)

第 ⑦ 步拆開來看:伺服器收到什麼、檢查什麼、最後留下什麼。

iPhone 送來的 印鑑證明(attestation object) Apple 簽發的憑證 · 公鑰(章的樣本) · 用 challenge 算的指紋 · Apple 的簽名 · App ID · counter = 0 · 開發/正式環境標記 號碼牌 keyId=公鑰的指紋 公鑰不另外送,就在憑證裡 你的伺服器:五關都過才存 1 是 Apple 開的嗎?憑證一路驗到 Apple 根憑證 ✓ 2 是為這次 challenge 開的?跟自己記下的 challenge 比對 ✓ 3 是這顆章嗎?憑證裡公鑰的指紋 = keyId ✓ 4 是我的 App 嗎?App ID 是我的 ✓ 5 全新、環境對嗎?counter=0、環境標記對 ✓ 任一關不過 → 拒絕,什麼都不存 留下來的 存起來 公鑰 ↔ 這位使用者 之後每次蓋章都拿它比對 用完就丟的 ✕ challenge(一次性) ✕ 印鑑證明(只用這一次)

圖 B:伺服器怎麼處理印鑑證明。五關依序亮起;全過才把憑證裡的公鑰存起來(點圖可放大)

實作時照 Apple 官方的 11 步驗證清單逐條寫;每一步都屬於上面五題之一。

第二段:每次請求(蓋章)

註冊完之後就不用再找 Apple,手機自己蓋章。

iPhone(本機完成,不連 Apple) clientData請求內容+challenge SHA256算出指紋 Secure Enclave用私鑰蓋章counter 7 → 8 請求改一個字 → 指紋不同 → 章對不上 你的伺服器 驗證 assertion用存檔的公鑰驗章 ✓challenge 對得上 ✓counter 8 > 上次的 7 ✓通過 → 把 8 存起來 送出 攻擊者重送舊的 assertion裡面的 counter 還是 7 7 沒有大於 8→ 拒絕

圖 C:每次請求。請求內容被綁進章裡;counter 每蓋一次就 +1(點圖可放大)

伺服器收到後確認四件事,全過才相信這個請求:

確認代表什麼
用存檔的公鑰驗章,通過是那顆註冊過的章,而且請求內容沒被改過
challenge 是我剛發的這張單子是現在寫的
App ID 是我的是我的 App 蓋的
counter 比上次大不是舊單子拿來重送(通過後記下新的 counter)

counter 為什麼擋得住重送?

counter 本身被蓋在章裡,改了章就對不上;而且它只會變大。伺服器記得上次是 7,攻擊者錄下來重送的舊單子還是 7 → 拒絕。

challenge 已經能擋掉大部分重送;counter 是第二道保險,還多一個好處:如果伺服器看到 counter 停住或倒退,可能有一個被改過的 App 複本在冒用 —— 這是可疑訊號。

常見的坑

✔ 過關標準

能不看筆記回答下面 4 題,這站就過了。

  1. 註冊和蓋章各做什麼?哪個要連 Apple?看答案收合
    註冊(attestation):裝好 App 後做一次(重裝、換機、還原才重做),請 Apple 替新的章作證,要連 Apple。蓋章(assertion):之後每個重要請求都做,手機本機完成,不連 Apple。
  2. 註冊時伺服器要問哪五個問題?看答案收合
    是 Apple 開的嗎?是為這次的 challenge 開的嗎?講的是這顆章嗎?是我的 App 嗎?是全新、環境對的章嗎?
  3. counter 為什麼能擋重送?看答案收合
    counter 被蓋在章裡改不了,而且只會變大。伺服器記得上次的值,舊單子的 counter 不會比它大,所以重送會被拒。
  4. 什麼情況要重新註冊?伺服器該怎麼看待新章?看答案收合
    重裝、換機、從備份還原,或 keyId 弄丟。這些都是正常情況,伺服器不該一看到新章就拒絕。

下一站

Level 2 換到 Android,看 Google 怎麼解同一個問題、跟 Apple 最大的不同在哪。

參考來源