WWDC Quick Look 💓 By SwiftGGTeam
App Attest で App を保護する

App Attest で App を保護する

元の動画を見る

ハイライト

App Attest は Secure Enclave を使って、エクスポートできないハードウェア紐づけキーを生成し、リクエストが実際の Apple デバイス上で動く改ざんされていない App から来ていることを、サーバーに暗号学的に証明します。iOS 27 では launch validation category と bundle version の拡張フィールドが追加され、macOS 27 では初めて App Attest をサポートし、ACL Blob OID によってシステム完全性を検証できます。さらに新しい Fraud Metric は、1台のデバイスが過去30日間に過剰な数のキーを生成した異常行動を検出できます。

主要内容

あなたがオンライン試験 App を作ったとします。学生が回答を送信すると、サーバーが採点します。攻撃者が App をリバースエンジニアリングし、改造版を作り、偽の高得点回答を直接サーバーへ送ります。サーバーから見ると、そのリクエストは通常のリクエストとまったく同じに見え、判別できません。

App Attest はこの問題を解決するための仕組みです。

中核となる考え方はシンプルです。デバイス上の Secure Enclave が鍵ペアを生成し、秘密鍵は常にハードウェア内に留まります。公開鍵のハッシュが key ID として App に返されます。App はこの key ID をサーバーに送り、サーバーは challenge を返します。App はその challenge を使って Apple に attestation(証明)の生成を依頼します。この attestation には証明書チェーン、デバイスハードウェアのスナップショット、App の識別情報が含まれます。サーバーが検証すれば、そのリクエストが本当に実際の Apple デバイス上で動く改ざんされていない App から来ていると確認できます。

(01:53) 以前の改ざん対策は、脱獄検出やデバイスフィンガープリントに依存し、攻撃者との終わりのない攻防になりがちでした。App Attest は信頼の根を Apple のハードウェアと Secure Enclave に置きます。攻撃者は秘密鍵をエクスポートできず、attestation を別のデバイスで再利用することもできません。

(02:15) デバイスが本物であることを証明するだけでなく、App Attest は App が改変されているかどうかも明らかにできます。relying party identifier(Team ID + Bundle ID の連結)であなたの App を識別します。攻撃者が再署名すると Team ID が変わり、その違いは attestation に現れます。

(03:03) iOS 27 では2つの重要なシグナルが追加されました。launch validation category は App が App Store、TestFlight、その他のどの経路から起動されたかを示し、bundle version は実行中の App があなたの公開したバージョンかを確認できます。攻撃者が Bundle Version を上げて再署名しても、その変化は attestation に露出します。

(04:08) macOS 27 は初めて App Attest をサポートします。これは金融やゲームのチート対策など、Mac 上の高価値ビジネスにとって大きな意味があります。Mac エコシステムは iOS より開かれており、ユーザーは SIP(System Integrity Protection)を無効化したり、セキュリティポリシーを下げたりできます。Apple は macOS の証明書チェーンに ACL Blob OID を追加し、キー生成時にデバイスが Full Security モードであったか、SIP が有効だったかを記録します。

(16:27) Fraud Metric は今回もっとも興味深い新機能です。これは古くからある問題に答えます。攻撃者が数百台の実機でデバイスファームを作る場合、各デバイスは本物なので、attestation だけでは止められません。Fraud Metric は、1台のデバイスが過去30日間に生成した一意の attested key 数の概算値を返します。通常のユーザーなら1台のデバイスに1つのキーです。この指標が急上昇していれば、そのデバイスが大量に資格情報を生成している、または他のデバイスのために attestation を署名する broker として使われている可能性があります。

詳細

利用可否を判断する

(04:26) App Attest は、新たに加わった macOS 27 を含むすべての Apple プラットフォームをサポートします。ただし、すべての App 種別で利用できるわけではないため、isSupported で判断する必要があります。

import DeviceCheck

if DCAppAttestService.shared.isSupported {
    // App Attest を利用できるため、通常どおり統合する
} else {
    // リスクシグナルとして扱い、機密性の高い機能を制限する
}

重要な点:

  • Action と SSO App Extension はサポートされますが、その他の Extension 種別はサポートされません。
  • isSupported == false そのものを fraud signal としてリスク評価に組み込めます。
  • iPhone 15 を名乗るデバイスが頻繁に非対応を返す場合、改ざんされている可能性があります。

キーを生成する

(05:07) App は generateKey() を呼び出し、Secure Enclave に紐づく鍵ペアを生成します。

import DeviceCheck

let keyID = try await DCAppAttestService.shared.generateKey()
// keyID を Keychain に保存する

重要な点:

  • 秘密鍵は Secure Enclave に保存され、エクスポートできません。
  • ユーザーごと、またはデバイスごとに1つのキーを生成し、ユーザー間で共有しないでください。
  • キーは App 更新後も有効ですが、App の再インストールやデバイス復元(iCloud バックアップからの復元を含む)では無効になります。
  • キーはデバイス間で同期されません。

Attestation をリクエストする

(06:32) キー生成後、App はサーバーから challenge を取得し、attestation API を呼び出します。

import DeviceCheck

let keyId: String = fetchKeyIdFromKeychain()
let clientDataHash: Data = sha256(serverChallenge)

let attestation = try await DCAppAttestService.shared.attestKey(
    keyId: keyId,
    clientDataHash: clientDataHash
)
// attestation をサーバーへ送信して検証する

重要な点:

  • サーバーが attestation の開始を制御し、リクエスト頻度も制御する必要があります。
  • 失敗時には指数バックオフ(exponential back-off)を実装し、リトライロジックをハードコードしないでください。
  • ユーザーフローをブロックしないよう、バックグラウンドタスクで実行します。
  • 検証は必ずサーバー側で行い、クライアント側の検証結果を信頼してはいけません。

Attestation オブジェクトは3つの部分を含みます。format(Apple の匿名証明を表す固定文字列)、attestation statement(証明書チェーンと receipt)、authenticator data(App と証明に関する情報)です。

証明書チェーンは、キーが実際の Apple ハードウェア上で生成されたことを証明します。leaf certificate には nonce、key ID、relying party identifier が含まれます。macOS 27 ではさらに ACL Blob OID が含まれ、Full Security モードと SIP の状態を記録します。

(10:28) iOS 27 の authenticator data の末尾には extensions 構造が追加され、2つのフィールドを含みます。

  • launch validation category:App Store、TestFlight、またはその他
  • bundle version:現在実行中の App バージョン

サーバーはこれらのフィールドの異常値を監視し、リスク評価に組み込むべきです。

Assertion を生成して通信を保護する

(12:33) Attestation の検証に成功した後、App は同じキーを使って assertion を生成し、その後のリクエストを保護できます。

import DeviceCheck

let keyId: String = fetchKeyIdFromKeychain()
let clientDataHash: Data = sha256(serverChallenge)

let assertion = try await DCAppAttestService.shared.generateAssertion(
    keyId: keyId,
    clientDataHash: clientDataHash
)
// assertion をリクエスト payload に埋め込んでサーバーへ送信する

重要な点:

  • Assertion はデバイスローカルで生成され、Apple サーバーを経由しないため、必要に応じてリアルタイム生成できます。
  • 暗号演算を伴い CPU コストがあるため、高頻度の大量生成は避けます。
  • サーバーは assertion 内の counter が厳密に増加していることを検証し、リプレイ攻撃を防ぐ必要があります。
  • counter が変わらない、または減少する場合、改ざんされた App のコピーである可能性があります。

よくある落とし穴

(15:02) つまずきやすい点はいくつかあります。

ユーザーが App を再インストールしたりデバイスを復元したりすると、key rotation が発生します。新しいキーを即座に拒否してはいけません。過去のキー記録を保持し、Fraud Metric と組み合わせて異常行動かどうかを判断します。

検証に失敗しても、ユーザーをすぐに遮断しないでください。まず機能を段階的に制限します。たとえば出金額を制限したり、機密データを隠したりします。同時に監視を強化し、限定的なアクセスは許可します。

Fraud Metric

(16:35) Fraud Metric は、compromised されたデバイスが broker として他のデバイスのために attestation を署名する攻撃パターンを検出します。サーバーは attestation 内の receipt を使って Apple の App Attest data server に POST リクエストを送り、fraud metric を取得します。

返される receipt には署名、証明書チェーン、payload が含まれます。その中の risk metric フィールドが fraud metric のカウントです。このカウントは概算値で、過去30日間にそのデバイス上で生成された一意の attested key の数を表します。

receipt には not beforeexpiration time フィールドで制御される更新ウィンドウがあります。通常ユーザーの App 再インストールやデバイス復元も fraud metric に寄与します。そのため、この値だけでユーザーをブロックしてはいけません。調査シグナルとして扱い、ベースラインを監視し、異常なピークを識別します。

重要な示唆

金融 App に取引署名を追加する

何をするか:送金や支払いなどの重要操作の前に、App Attest assertion で取引 payload に署名し、サーバー検証後にのみ実行します。 なぜ価値があるか:攻撃者がユーザーのパスワードを入手しても、改ざんされた App から有効な取引リクエストを送れません。 どう始めるか:取引送信前に generateAssertion を呼び出し、assertion と取引データを一緒にサーバーへ送り、バックエンドで assertion の署名と counter を検証します。

ゲームにランキング不正対策を追加する

何をするか:プレイヤーがスコアを送信するときに assertion を添付し、サーバーが App が改変されていないことを確認してからランキングに反映します。 なぜ価値があるか:攻撃者がチートメニューを注入して偽の高得点を送信するのを防げます。 どう始めるか:スコア送信 API で assertion を必須にし、launch validation category と bundle version も監視します。異常値は直接拒否します。

Fraud Metric でデバイスファームを識別する

何をするか:Fraud Metric をリスク制御エンジンに接続し、異常なデバイスをマークします。 なぜ価値があるか:デバイスファーム内の各デバイスは実機なので、従来のデバイスフィンガープリントでは止められません。しかし Fraud Metric は、1台のデバイスが大量にキーを生成している行動を露出します。 どう始めるか:サーバーが定期的に receipt を更新して fraud metric を取得し、しきい値アラートを設定し、他のリスク特徴と組み合わせて総合判断します。

macOS App に完全性チェックを追加する

何をするか:macOS 27 で初めて App Attest がサポートされました。ACL Blob OID を使って、デバイスで Full Security と SIP が有効かを検証します。 なぜ価値があるか:企業向けソフトウェアや有料ツールなど、Mac 上の高価値ビジネスには、以前は信頼できる改ざん対策が不足していました。 どう始めるか:attestation 証明書チェーン内の ACL Blob OID を解析し、Full Security と SIP の状態を確認します。SIP が無効なデバイスは高リスクとしてマークします。

isSupported を最初のリスク制御ゲートにする

何をするか:isSupported の戻り値をユーザーのリスク評価に組み込みます。 なぜ価値があるか:脱獄デバイスや改ざん環境では App Attest が利用できない場合があり、このシグナル自体が異常指標になります。 どう始めるか:ユーザーごとの isSupported 応答履歴を記録し、突然大量の false が現れたデバイスを重点的に監視します。

関連セッション

  • WWDC26 基調講演 — WWDC26 のオープニング。Apple プラットフォームにおける新しいセキュリティの方向性を概観
  • セキュリティのエージェント活用 — セキュリティ領域のエージェント型アプリケーション。App Attest のリスク制御の考え方を補完
  • 379 Trust Insights — Trust Insights 関連のセッション。セキュリティ評価とリスク制御を扱う
  • App Store — App Store の配布と検証。launch validation category に関連
  • Swift — Swift 言語の新機能。セキュリティに関わる言語レベルの改善を含む可能性

コメント

GitHub Issues · utterances