※2020/9/1執筆→11/16全体公開(忘れていました)
App Attest APIは、iOS 14以上で使用できる、DeviceCheckの一種です。
たとえばアプリがハックされると、チートや広告の削除、有料機能の不正利用などが行われます。
それを防ぐため、デバイスで特殊な暗号鍵を生成し、サーバーが機密データにアクセスする際にAppleの認証を受けることで、アプリが正当なことを証明できます。
アプリの実装方法
こちら参照。DCAppAttestServiceを用いて以下のように実装します。
1. API利用可否の判定
guard DCAppAttestService.shared.isSupported else {
log.error("Unsupported")
return
}
// サービス利用可
2. 暗号鍵の生成
DCAppAttestService.shared.generateKey { keyId, error in
guard error == nil, let keyId = keyId else {
log.error(error.debugDescription ?? "Unknown error")
return
}
// KeyId生成完了
}
3. チャレンジの要求
サーバー(Your server)にKeyIdを送り、チャレンジ(サーバーが決めたランダム値)を受け取ります。
let challenge = // サーバーから受け取る
4. keyIdとチャレンジを使って認証
let hash = Data(SHA256.hash(data: challenge))
DCAppAttestService.shared.attestKey(keyId, clientDataHash: hash) { attestation, error in
if let error = error {
log.error(error.debugDescription)
} else if let attestation = attestation {
// 認証OK/NG判定
} else {
log.error("Attestation is null")
}
}
ここまでは、アプリ起動時に1回だけ行えばよい
5. アプリの正当性の主張
以後、サーバーリクエスト毎に、アプリの正当性を主張します。
今回はチャレンジとサーバーリクエスト内容を組み合わせたハッシュを作成します。
let challenge = // サーバーから受け取る
let request = [ "action": "getUser",
"userId": "1234",
"challenge": challenge ]
guard let clientData = try? JSONEncoder().encode(request) else { return }
let hash = Data(SHA256.hash(data: clientData))
service.generateAssertion(keyId, clientDataHash: hash) { assertion, error in
if let error = error {
log.error(error.debugDescription)
} else if let assertion = assertion {
// 正当性OK/NG判定
} else {
log.error("Assertion is null")
}
}
サーバーの実装方法
こちら参照。やることは以下
・(Your Appに対して)チャレンジの払い出しと保持
・(App attestに対して)認証オブジェクトの生成
※サーバーの実装方法はよくわかっておらず、調査中
DeviceCheckについて
App Attest単体では、不正を行ったデバイスの特定はできないので、特定したい場合DeviceCheckと併用します。
DeviceCheckは、こちらの記事が分かりやすいです。