はじめに
はじめまして。セキュリティ開発チームのキム・ ドヨン、キム・ヨンヒョン、パク・ギョンジュン、フバイン・チャールズ、アン・サンファンと申します。私たちが所属しているチームは、LINEヤフーの全般的なセキュリティを強化するため、セキュリティ技術の研究開発および各サービスを対象としたセキュリティコンサルティングを担当しています。本稿では、サービスに対するリクエストが正規のデバイスとアプリから送信されたリクエストであることを証明するデバイス証明(Device Attestation)サービスを紹介したいと思います。
デバイス証明サービス開発の背景
LINEヤフーのサービスが社会の基盤インフラとなり、これを悪用して不正な目的を達成しようとする事例も増えてきました。攻撃者はアカウントの乗っ取りやスパム(spamming)、フィッシング(phishing)、詐欺(fraud)などを目的にサービスを利用し、そのために自動化されたプログラムを使用して大量のサービスリクエストを送ったり、アプリを改ざんして悪意のある行為を行ったりします。
従来のソフトウェアベースのセキュリティ対策は、ルート権限を持つ攻撃者を想定した脅威モデルにおいて脆弱です。攻撃者はアプリの実行結果を自由に改ざんできるため、アプリに内包されるロジックをもとにしたセルフチェックを正しく行うことはできません。
近年の攻撃技法はますます巧妙になってきており、われわれの防御システムの弱点を標的にしたあらゆる手法を用いた攻撃に直面しています。攻撃者によるアクセスと、サービスによる信頼できるアクセスを的確に区別するのは非常に困難です。
従来型の異常検知もある程度は効果がありますが、攻撃者による改ざん・悪用をすべて検知できる万能なものではありません。また、ユーザー生成コンテンツの量とその多様性が爆発的に増加し、これに対応していくためには、バリエーションに富んだコンテンツと、悪用への防御を一体となって実現できるようなシステムが求められます。
これらの状況を踏まえて、私たちは個別の悪用のケースに対処するのではなく、根本的なサービスの悪用の原因に焦点を当てることが重要であると考えました。
私たちは攻撃者による異常なアクセスの大部分は、不正なデバイスやアプリで生成されているという点に着眼し、デバイスのハードウェアベースの証明方式を用いたアプローチに基づいて攻撃者の実行環境自体を制限するようにしてアビューザーからの攻撃を効果的に低減させ、デバイスの信頼の基点(Root of Trust)と暗号学的メカニズムを活用することで、正しいデバイスを識別でき、運用中の乱用防止対策を組み合わせてその効用性を最大化することを実現しました。
デバイス証明サービスは、Auth & Account DevチームとAccount Product App Dev 1チーム、Platform Product Managementチームと協業し、2023年12月にLINEサービスに成功裏に導入することができました。これに基づき、さまざまな形態のサービスリクエストの検証およびモニタリングに活用しています。また、私たちのチームは金融サービスのように高いセキュリティレベルが要求されるサービスにデバイス証明サービスを統合する作業も同時に進めています。
それでは、デバイス証明サービスが具体的にどのように機能するのか、ご説明いたします。
デバイス証明(Device Attestation)サービスとは
デバイス証明(Device Attestation)サービスは、サービスに対するリクエストが正規のアプリと真正なデバイスから送信されたリクエストであることを確認します。
- 真正なデバイスと正規のアプリから送信されたものである
- サービスのリクエストの内容も改ざんされていない
具体的には、デバイス証明サービスは、次のような事例に該当するサービスのリクエストを「潜在的に危険性が高い」とみなし、モニタリングしてサービスの悪用を防止することを目標とします。
- エミュレーターおよびスクリプトからのリクエスト
- 改ざんされたアプリからのリクエスト
- Jailbreakおよびroot化されたデバイスからのリクエスト
- 中間者攻撃(Man-In-The-Middle, MITM攻撃)
- 再送攻撃(Replay Attack)
デバイス証明サービスは公開鍵認証基盤(Public Key Infrastructure, PKI)に基づき、全体像は以下の通りです。
- TEE(Trusted Execution Environment): デバイス内にハードウェア支援を用いた隔離実行環境として、セキュリティ的に信頼可能な高信頼実行環境を指します。TEE 内のデータは、その環境外のコード(例えば、App,OS レベルでのアクセス)で読み取ったり改ざんしたりできません。
- デバイス証明クライアント(Device Attestation Client): デバ イス証明サービスを提供するクライアントモジュールです。デバイス内のTEEおよびデバイス証明サーバと相互作用します。
- デバイス証明サーバ(Device Attestation Server): デバイス証明サービスを提供するサーバモジュールです。TEEで生成された非対称鍵のうち、公開鍵はデバイス証明サーバに保存されます。
デバイス証明の仕組みを簡単に説明すると、まずデバイス証明クライアントがサービスのリクエストが潜在的に危険性の高い環境からのものであるかを検証するためにデバイス証明サービスに必要なデータを生成します。この過程でTEEはTEEで生成された秘密鍵でサービスのリクエストに署名し、リクエストの正当性を確保します。デバイス証明クライアントによって生成されたデータはデバイス証明サーバに送信され、サーバはこのデータを検証してサービスのリクエストの潜在的危険性を判断します。
上記の方法で、ユーザーがアプリ内で操作(ログイン、決済、送金など)を行ったら、サーバはデバイス証明サービスを利用して、ユーザーからのサービスのリクエストが改ざんされたアプリや信頼できない環境で発生したかどうかを確認します。確認の結果、問題がある場合、サーバはアビュージングや不正アクセス、攻撃などの不正使用を抑制するための適切な措置を講じることができます。
デバイス証明サービスは、Androidのキー証明(Key Attestation)とiOSのアプリ証明(App Attest)機能をもとに実装しました。プラットフォームごとに実装方式に違いがあるため、このような機能の不一致を解消し、AndroidとiOSの両方で一貫したセキュリティアーキテクチャを実現するためにWebAuthn仕様をもとに再設計し、また、ライブラリとしても提供しており、アプリおよびサーバ開発者のデバイス証明機能をサービスに簡単に統合できるようにしています。
次に、デバイス証明サービスで使用される認証プロトコルであるAttestationとAssertionとは何かを概説します。そして、クライアント、TEE、およびサーバの間でどのようなプロセスで行われるのか、また、この過程でどのような方法でアプリとデバイスの改ざんの有無を検証できるのかを技術的に詳しく説明します。
Attestation
Attestationは認証に使われるアサーションキー(assertion key)を登録する過程です。キーの生成環境の信頼性および正当性を保証する重要なステップとして、以下を保証します。
- 信頼の基点(Root of Trust)の確認: キーを生成する際に、ハードウェア上に保護領域で生成されたことをデバイスの信頼の基点を通じて証明します。
- デバイスの属性の識別: 使用中のデバイスの特定の属性を識別します。(秘密鍵の保護方法、ブート状態の検証の有無など)
サーバはセキュリティレベルの高い環境でキーが生成され、デバイスがRoot化やJailbreakのようなセキュリティの脅威がない安全で信頼できる状態であることを確認できます。証明の過程でアプリの完全性に関する情報もともに伝達され検証されるので、正規のアプリが信頼できる環境で実行されていることも保証されます。
Attestationはまた、署名を通じてアサーションキーペアの公開鍵がサーバに送信される間、改ざんされないように保護する役割も果たします。これにより、キーの生成から転送までの全過程を安全に管理し、 キーの完全性と真正性を保証します。これらのメカニズムにより、サーバはクライアントからのリクエストが信頼できるソースからのものであることを確信できます。
Attestation プロセス
Attestationプロセスにおいて、クライアントとサーバは再送攻撃を防ぐために以下のチャレンジレスポンス認証に従ってやりとりを行います。
- クライアントはサーバにチャレンジを要求し、受け取ります。チャレンジは一回限り使用するランダム値で、再送攻撃を防ぐために必要です。
- クライアントはTEEでアサーションキーペア(非対称鍵)を生成します。秘密鍵はそのキーの生成を要求したアプリのみが使用でき、ハードウェア上に保護領域で生成および保護されるため、その環境外での外部コードによって読み取られたり改ざんされたりはできません。
- Android: ARM TrustZoneまたはStrongBoxでアサーションキーペアと、そのキーに対するX.509証明書チェーンを生成する
- iOS: Secure Enclave(SE)でアサーションキーペアを生成する
- クライアントはアサーションキーペアの公開鍵とデバイスおよびアプリに関連する情報を安全にサーバに伝達するために、複数のセキュリティメカニズムを用いてAttestationオブジェクトを生成します。Attestationオブジェクトはプラットフォームごとに異なるため、詳細な説明は以下のAttestationオブジェクトのセクションの内容を参照してください。
- Android: TEEでアサーションキーペアの公開鍵を含むX.509証明書を生成し、これに関連する上位証明書のリストとともにクライアントに伝達します。クライアントは証明書のリストとチャレンジを含む複数の情報をもとに生成した署名値などでAttestationオブジェクトを生成します。
- iOS: クライアントはAppleサーバにアサーションキーペアの公開鍵と複数の検証用情報を一緒に伝達し、Attestationオブジェクトの生成を要求します。Appleサーバは伝達されたデータを検証し、問題がなければアサーションキーペアの公開鍵およびチャレンジと検証用情報の組み合わせをSHA-256でハッシュ化したノンス(nonce)を含むX.509証明書が含まれたAttestationオブジェクトを生成し、クライアントに伝達します。
- 生成されたAttestationオブジェクトをサーバに伝達します。
- Attestationオブジェクトを受け取ったサーバは、各プラットフォームのルート証明書でAttestationオブジェクト内のX.509証明書チェーン全体の有効性と署名、チャレンジ値およびアプリの署名値を含む固有情報を検証します。これにより、伝達されたアサーションキーペアの公開鍵が信頼できるデバイスおよび改ざんされていないアプリで生成されたことを保証できます。検証結果に問題がなければ、最終的に公開鍵をユーザー情報とともに登録することでAttestationプロセスは完了します。
X.509 証明書チェーン検証 アサーションキーペアがハードウェア格納型キーペアとして、デバイス内のハードウェア上の保護領域で生成されたことを証明する必要があります。デバイスの信頼の基点に基づいて生成された証明書チェーンを検証することにより、キーの真正性と証明の信頼性 を保証できます。 Attestationオブジェクト内のX.509証明書チェーンは、大きく3つの証明書で構成されています。
証明書チェーンは、アサーションキーペアの公開鍵の情報を含むリーフ証明書から始まり、ルート証明書で終わる証明書のリストで構成されます。各証明書は、その上位段階の証明書で検証する過程を繰り返し、ルート証明書に到達するまで継続して逆追跡します。このプロセスを通じてルート証明書までの検証に成功すると、アサーションキーが信頼できるデバイスおよび改ざんされていないアプリで生成されたものであることを保証できます。 |
Attestationオブジェクト
Attestationオブジェクトは、Attestationに必要な認証データを含むデータ構造です。FIDO2 WebAuthnで定義されたAttestationオブジェクトの構造をもとに、下図のような構造になっています。
出典: FIDO2 WebAuthn
iOSはAppAttest APIを通じてすでにWebAuthnのAttestationオブジェクト形式で直列化されたデータを返送するのに対し、Androidは生成されたキーペアのプロパティに対する証明書チェーン自体を返還します。したがって、形式の不一致が発生するため、私たちはサーバロジックを最大限に統合し、二つのプラットフォームの要請をすべて処理できるようにAndroidでも同じ構造のAttestationオブジェクトを使用することにしました。
Attestationオブジェクトの基本構造は、AndroidとiOSの両方で大きく3つに分けられます。
- fmt: 証明文形式(attestation statement format)です。「packed」、「tpm」、「android-safetynet」、「fido-u2f」、「none」、「apple」などの値が入り、証明文形式の値によってattStmtの形式が異なります。
- attStmt: Attestation Statementの略で、改ざんされていないアプリやデバイス、またデバイス内ハードウェア上に保護領域でキーが生成されたことを保証する証明書チェーン(certificate chain, x5c)と認証者データ(authData)およびチャレンジをアサーションキーで署名した値が含まれている証明文となります。その後、サーバはAttestationオブジェクトを検証する際に証明書チェーンを検証することによって、改ざんされていないアプリやデバイス、またデバイス内ハードウェア上に保護領域でキーが生成されたことを確認し、認証者データを公開鍵で検証し、認証データが改ざんされていないことを確認します。
- authData: 認証者データ(authenticator data)で、アサーションキーペアの公開鍵および認証に関連するデータが含まれます。
fmtはプラットフォームや認証者によってその値が異なります。デバイス証明サービスの認証子でAttestationオブジェクトのfmtはAndroidの場合、android-keyを使用し、iOSではapple-appattestを使用します。
fmtによって異なりますが、attStmtの形式は基本的にalgとsig、x5cの三つで構成されます。
- alg: アルゴリズムはP256楕円曲線をベースとしたECDSAであるES256を使用します。
- sig: authDataとチャレンジなどを組み合わせて、アサーションキーで署名した値です。Androidでは、この値によりAttestationオブジェクト内のデータが改ざんされていないことを保証します。
- Android: この値によりAttestationオブジェクト内のデータが改ざんされていないことを保証します。
- iOS: このフィールドは存在しません。代わりに、authDataとチャレンジの組み合わせをハッシュすることによって生成された nonce 値が x.509 証明書に追加され、データが改ざんされていないことが保証されます。
-
x5c: リーフ証明書と中間証明書を含まれています。ルート証明書はAndroidとiOSの公式サイト(Android、iOS)でご確認いただけます。
authDataは以下の値で構成されます。
- RP ID Hash: AndroidとiOSの両方にアプリID値をSHA-256 ハッシュ演算した値が入ります。
- Android: attStmt内の証明書チェーンに含まれているAttestationApplicationIdを検証し、アプリの改ざんの有無を確認できます。
- iOS: サーバは公式アプリIDを持っているため、RP ID Hash値と比較してアプリの改ざんの有無を確認できます。RP IDはアプリのApp IDをハッシュした値で、これには10桁のチーム識別子、ピリオド、そしてアプリのBundle ID値が含まれます。もし、第三者がアプリを改ざんするためには、Appleから新しいBundle IDとプロビジョニングプロファイルを取得しなければならないため、RP ID Hash値が変わります。したがって、サーバはアプリの改ざんの有無を確認できます。
- flags: authDataの状態(state)を表す1byte長さのフラグです。各bitは、それぞれ「ED」、「AT」、「BS」、「BE」、「UV」、「UP」の値を持ちます。ATは、下に出てくるattested cred dataを含むbitで、この値が1になると、認証データにattested cred dataが含まれていることを意味します。Attestationオブジェクトの場合、ATは1になります。
- counter: 署名カウンタであり、Attestationオブジェクトでは値が0になります。証明が正常に完了すると、Credentialの署名カウンタが0に設定され、その後、Assertionが正常に完了するたびに1ずつ増加します。
- attested cred data: Attested credential dataの略です。以下のフィールドが含まれています。
- aaguid: Authenticator attestation global unique identifierの略で、128bitの識別子です。
- credentialIdLength: 符号なしビッグエンディアン整数(unsigned big-endian integer)の値で、以下のcredentialIdの長さを示します。
- credentialId: 生成されたアサーションキーの識別子です。
- credentialPublicKey: アサーションキーペアの公開鍵の値がCOSE_Key形式でEncodeされています。
- extensions: 追加のデータを入れるときに使用するフィールドで、デバイス証明の認証者では使用していません。
Assertion
Assertionとは、Attestationによって確保した信頼に基づき、クライアントがアサーションキーを所持していることを証明することで(proof of possession)アプリとサーバ間の安全な通信を保証します。
Assertionプロセスは、通常、アプリ内で重要なイベントが発生したときに実行されます。Assertion実行時、アプリはサーバからチャレンジ値を受け取り、これをアサーションキーで署名した後、サーバに送信します。サーバは受信した署名を検証し、サービスのリクエストが信頼できるアプリから来たものかどうかを確認できます。Assertionの過程でアプリの完全性に関する情報も一緒に伝達され検証されるので、アプリの改ざん有無も一緒に証明できます。また、AssertionはAttestationの証明プロセスで確保したキーの安全性に基づいて作動するため、キーの機密性と完全性も維持されます。
Assertionプロセス
Attestationプロセスと同様に、クライアントとサーバは再送攻撃を防ぐために以下のチャレンジレスポンス認証に従ってやりとりを行います。
- クライアントはサーバにチャレンジをリクエストし、受け取ります。
- クライアントは、Attestationプロセスを通じて登録されたアサーションキーでAssertion関連情報やチャレンジなどを署名します。
- クライアントは、生成された署名を含むAssertionオブジェクトを生成します。(Assertionオブジェクトについては、以下で詳しく説明します)
- Assertionオブジェクトがサーバに送信されると、サーバはAssertionオブジェクトの情報と証明プロセスを実行し、保存したアサーションキーの公開鍵を使用して署名を検証し、クライアントとアプリが正常な環境で動作していることを確認します。
Assertionオブジェクト
Assertionオブジェクトは、署名値と認証データ値を含むデータ構造です。認証データ形式は、Attestationオブジェクトの認証データ形式と同じです。
- signature: authenticatorData値とclientDataをSHA-256 ハッシュ演算した値を接続(concatenate)し、この値をアサーションキーで署名した値です。
- authenticatorData
- RP ID Hash: AndroidとiOSの両方にアプリID値をSHA-256 ハッシュ化した値が入ります。
- iOS: RP ID Hashにより、サーバはアプリケーションの完全性を確認できます。また、iOSのAppAttestサービスを実行するiOSデーモンは、アプリのBundle IDに基づいてACLを管理します。このACLは、特定のBundle IDにのみキーのアクセスを許可します。したがって、アプリが改ざんされてBundle IDが変更されると、新しいBundle IDを認識できず、元のキーにアクセスできません。
- Android: RP ID Hashをサーバで検証することはありませんが、プラットフォームACLの観点からは本質的にiOSと同じです。もし攻撃者または第三者がアプリを改ざんするには、アプリを再署名する必要があるため、署名値が変更されます。AndroidのKeyMasterサービスは、各キーに対するアクセス権限リスト(ACL)を管理し、このACLは特定アプリケーションの署名にのみキーアクセスを許可します。したがって、アプリが改ざんされて再び署名されると、KeyMasterは新しい署名を認識できず、元のキーにアクセスできません。
- RP ID Hash: AndroidとiOSの両方にアプリID値をSHA-256 ハッシュ化した値が入ります。
- flags: AT値が0にセットされています。つまり、先にAttestationオブジェクトで調べたattested cred dataがAssertionオブジェクトにはありません。
- counter: 署名カウンタでアサーションキーの累積使用回数を示し、再送攻撃を防止する補助手段として使えます。最初のAssertion時には、この値は必ず0より大きくなければならず、サーバはAssertionごとにcounterが以前の値より大きいことを確認して、再送攻撃(Replay Attack)とキーの複製(Key Cloning)を探知できます。
セキュリティ強化対策
デバイス証明サービスは、アプリのセキュリティレベル を最大限に高めるため、次のようなセキュリティ強化対策を策定しました。
APIをAssertionにバインディング
ユーザーが決済や送金などのセキュリティの観点から重要な作業を行う際、該当APIのパラメータ値をAssertionにバインディングし、サービスのリクエストの真偽を保証できます。
例えば、ユーザーが決済や送金をサーバに要請する際に、アプリケーションが関連するリクエスト情報をAssertionオブジェクトに含めると、サーバではこれを検証することで、その情報が正規のアプリで生成されたことが確認でき、これによってAPIのセキュリティレベルを大幅に高められます。
潜在的に信頼できない実行環境の検出
Androidでは、Attestationオブジェクト内の証明書チェーンにキー証明拡張データスキーマ(Key Attestation Extension Data Schema)が含まれています。このスキーマの各要素の値を確認すると、実行環境に関する詳細な情報が得られます。
SecurityLevel ::= ENUMERATED {
Software (0),
TrustedEnvironment (1),
StrongBox (2),
}
RootOfTrust ::= SEQUENCE {
verifiedBootKey OCTET_STRING,
deviceLocked BOOLEAN,
verifiedBootState VerifiedBootState,
verifiedBootHash OCTET_STRING,
}
VerifiedBootState ::= ENUMERATED {
Verified (0),
SelfSigned (1),
Unverified (2),
Failed (3),
}
上記スキーマの各要素値が以下のような場合、「潜在的に信頼できない実行環境」とみなします。
attestationSecurityLevel
値がSoftware
に 設定されている場合- セキュリティレベルの低いデバイス(ハードウェアベースの鍵リポジトリが提供されていない)またはエミュレーターで実行されている可能性が高いです。
DeviceLocked
値がFalse
に設定されている場合- ブートローダーがロック解除されています。これは、潜在的に署名されていないデバイスのイメージがフラッシュされる可能性がある状態を意味します。この場合、イメージがアプリケーションの署名検証を偽造したり、KeyMaster ACLを迂回できます。ブートローダーがロック解除された状態では、攻撃者がブート状態が検証された状態で公式イメージを使用して証明を通過した後、署名検証を偽造して鍵ACLを迂回する修正されたイメージをフラッシュできます。
VerifiedBootState
値がVerifiedに設定されていない場合- デバイスメーカーが提供する公式デバイスのイメージではなく、修正された状態です。つまり、信頼できません。
基本的には、attestationSecurityLevelがTrustedEnvironmentやStrongBoxであり、deviceLockedがTrue、VerifiedBootStateがVerifiedの場合、信頼できる環境とみなします。その他、鍵証明拡張データスキーマにおける各要素、例えばOSパッチレベルが基準値より低すぎる場合などの情報に基づいて、より精巧なセキュリティポリシーを確立でき、その環境でのリクエストを遮断したり、既存の異常検知システムで追加のリスク要因として扱うことができます。
証明鍵流出対策
証明鍵は、純正AppleハードウェアおよびGoogle CTS(Compatibility Test Suite)を通過し、認証されたAndroidハードウェアでのみ使用できます。GoogleとAppleは、もし証明鍵が流出したり、モバイルデバイスメーカーで証明鍵を誤って処理したり、サプライチェーンで攻撃者の攻撃と疑われる抽出が発生するなど、さまざまな理由で証明鍵を信頼できなくなった場合、キーを無効化できます。Googleは当該キーを証明書失効リスト(Certificate Revocation List、CRL)に追加し、Appleは当該デバイスに対する証明発行を中断します。
したがって、私たちは証明過程で該当アサーションキーの有効性を検証するとき、証明書チェーンの各証明書の状態を証明書失効リスト(CRL)と比較して確認しています。このリストはGoogleで管理し、こちらのサイトで確認できます。詳細については、Googleの証明書失効リストに関するガイドラインを参照してください。
デバイス証明の迂回防止対策
攻撃者は、デバイスのOSシステムを直接修正することなく、アプリとカーネルの脆弱性を悪用してルート権限を獲得できます。この場合、ブートレベルの整合性が損なわれることがないため、攻撃者はAttestationとAssertionプロセスをバイパスまたは改ざんするようにすることができます。その結果、改ざんされたデバイスを通じて他の装置(Bot、Emulatorなど)にAssertionを提供でき、攻撃者はこのような方法でサービス要請を悪用できます。したがって、このような方法の攻撃に対する保護が必要です。
このような行為を完璧に感知することは不可能に近いですが、異常検知に基づいて単一デバ イスで要請されたAttestation回数を測定し、リスクを評価するために追加のセキュリティ層を構築しました。
まとめ
今回の文では、デバイスとアプリ、サービスのリクエストの完全性を保証するデバイス証明サービスを紹介しました。デバイス証明サービスは現在LINEアプリに統合された後、安定化段階に達しており、サービス関連データを収集し、分析しています。今後、このデータを活用して既存の異常検知ベースのアンチ亜ビュージングシステムを改善し、その結果を後続のブログ投稿を通じて共有する計画です。
また、デバイス証明サービスをLINEのようなグローバル規模のサービスに統合する過程で、さまざまな試行錯誤を経験しました。この場を借りて、その過程で多大なご支援をいただいたAuth & Account Devチーム、Account Product App Dev 1チーム、Platform Product Managementチームに心より感謝申し上げます。また、Auth & Account DevチームでまもなくグローバルLINEサービスでのデバイス証明サービスの適用過程と結果を後日ブログで共有する予定ですのでぜひご期待ください。長文をお読みいただき、ありがとうございました。