Code Signing(コード署名)は、実行可能ファイルにデジタル署名を行い、開発者の真正性とアプリケーションの整合性を保証するメカニズムです。Androidでは、すべてのAPKファイルは、デバイスへのインストールまたはGoogle Playへの公開前に、証明書で署名される必要があります。Google、2024年によると、AndroidはJARベースのv1からストリーミングインストール用のv4まで、4世代の署名スキームをサポートしています。
重要ポイント
Code Signingは、開発者が実行可能コードに自身のデジタル証明書で署名する暗号化プロセスです。署名は非対称暗号化を使用して作成されます。開発者の秘密鍵がデジタル署名を生成し、公開鍵が証明書に埋め込まれます。誰でも公開鍵を使用して署名を検証できますが、署名を壊さずにコードを変更することは不可能です。
モバイル開発において、コード署名は3つの機能を果たします。第一に認証:ユーザーとプラットフォームはアプリケーション開発者を識別できます。第二に整合性:署名後のAPKの変更は署名を無効にします。第三に信頼できる更新:プラットフォームは、インストールされているバージョンと同じ証明書で署名されたAPKでのみアプリケーションの更新を許可します。
Androidアプリケーションのデジタル署名には法的な重要性があります。ロシアの法律(63-FZ)および欧州のeIDASによると、適格な電子署名は自署と同等です。ただし、自己署名証明書(Androidでは一般的な慣行)でAPKに署名することは適格ではありません。これは整合性を確認しますが、法的観点からは開発者の身元を確認するものではありません。
Androidは4つのAPK署名スキームをサポートしており、それぞれが以前のバージョンの問題を解決し、新機能を追加しています。すべてのスキームは1つのAPK内に共存できます。これは古いAndroidバージョンとの下位互換性のために必要です。
v1(JAR署名)スキームはAndroid 1.0で登場しました。META-INF/MANIFEST.MFのエントリを使用して、APKアーカイブ内の個々のファイルに署名します。欠点:攻撃者はAPKを変更(ファイルの追加または削除)し、残りのファイルに触れずに変更されたファイルのみに再署名できます。これにより、v1は特定の攻撃に対して脆弱になります。Android 7.0で導入されたv2(APK Signature Scheme)は、署名自体を除くすべてのバイトを含めてAPKファイル全体に署名し、選択的な変更の可能性を排除します。
| スキーム | Android | 特徴 | 鍵のローテーション |
|---|---|---|---|
| v1(JAR) | 1.0+ | ファイルごとの署名 | いいえ |
| v2 | 7.0+ | APK全体の署名 | いいえ |
| v3 | 9.0+ | 署名+ローテーション | はい |
| v4 | 11.0+ | ストリーミング+ADB | はい |
Android 9.0で導入されたスキームv3は、長年の問題を解決します。署名鍵が侵害されたり期限切れになったりした場合どうするか?以前は、署名鍵を変更するとアプリケーションが新しいものとして扱われ、既存のアプリケーションの上にインストールできませんでした。v3はローテーションメカニズムを追加します。APKには、古い鍵で署名されたローテーションの証明(proof-of-rotation)を含めることができます。システムはチェーンを検証し、新しい鍵で署名されたアプリケーションの更新を許可します。
Keystoreは、アプリケーションに署名するための秘密鍵と証明書を含む保護されたコンテナです。Android開発では、JKS(Java KeyStore)またはPKCS12形式が使用されます。KeystoreはJDKに含まれるkeytoolユーティリティで作成されます。ストレージ内の各鍵は別名(alias)で識別され、パスワードで保護されています。
Keystore内の証明書には、公開鍵と所有者情報(組織名、国、有効期間)が含まれています。Androidアプリケーションの場合、証明書は自己署名可能です。Googleは認証局(CA)を必要とせず、これがAndroidをiOSと区別しています。ただし、証明書の有効期間は少なくとも25年でなければなりません。アプリケーションは同じ鍵で更新されるからです。
# 署名用の新しいkeystoreを作成する
keytool -genkey -v -keystore my-release.keystore \
-alias my-app-alias \
-keyalg RSA \
-keysize 2048 \
-validity 10000
# keystoreの内容を表示する
keytool -list -v -keystore my-release.keystore
Androidは署名鍵に2つのアルゴリズムをサポートしています:RSAとECDSA。2048ビットの鍵サイズのRSAは事実上の標準であり、すべてのAndroidバージョンでサポートされています。曲線P-256を使用するECDSA(楕円曲線デジタル署名アルゴリズム)は、より小さい鍵サイズで同じ暗号強度を提供します。Android 9.0以降、モバイルデバイスでの検証が高速なため、ECDSAが推奨されています。
Android Gradle Pluginでは、モジュールレベルのbuild.gradleのsigningConfigsブロックを介して署名が設定されます。デバッグビルドの場合、Android Studioは既知のパスワードでデバッグkeystoreを自動的に作成します。リリースビルドの場合、開発者は自身のkeystoreへのパス、鍵の別名、パスワードを指定します。パスワードは、バージョン管理から除外された個別の設定ファイルに保存することをお勧めします。
現代的な実践は、CI/CDを介した集中署名管理です。Jenkins、GitLab CI、GitHub Actionsはkeystoreを保護されたアーティファクトとして、パスワードを環境シークレットとして保存できます。これにより、リポジトリを介した鍵漏洩を防ぎ、必要なときに鍵のローテーションを簡素化します。
// build.gradle(アプリレベル)— 署名設定
android {
signingConfigs {
release {
storeFile file("my-release.keystore")
storePassword System.getenv("KEYSTORE_PASSWORD")
keyAlias System.getenv("KEY_ALIAS")
keyPassword System.getenv("KEY_PASSWORD")
}
}
buildTypes {
release {
signingConfig signingConfigs.release
}
}
}
最大の互換性のために、APKは3つのスキームすべて(v1+v2+v3)で署名されるべきです。Android Gradle Pluginはデフォルトですべてのスキームを含みます。v2のみで署名されたAPKはAndroid 6.0以下ではインストールされません。v1のみのAPKはAndroid 7.0以上でv2の整合性上の利点を得られません。すべてのスキームを含めてもAPKサイズは1〜2%以上増加せず、あらゆるデバイスとの互換性を保証します。
Play App Signingは、アプリケーションの署名鍵を集中的に管理するGoogle Playサービスです。開発者はアップロード鍵(upload key)で署名されたAPKをGoogle Play Consoleにアップロードし、Google Playはユーザーに配信する前に配布鍵(distribution key)で再署名します。これにより、配布鍵の紛失や侵害から保護されます。
Play App Signingの利点:セキュリティ — 配布鍵はGoogleの保護されたストレージに保存されます。ローテーション — コンソールから鍵の変更をリクエストできます。復旧 — アップロード鍵を紛失した場合、新しい鍵を生成できます。欠点:Play App Signingの導入前に存在していたアプリケーションの場合、移行には新しいアプリケーションの作成が必要です。古い配布鍵が既に使用されているためです。
# 証明書のフィンガープリントを取得する(SHA-256)
keytool -list -v -keystore my-release.keystore \
-alias my-app-alias | grep "SHA256"
# apksignerでAPK署名を検証する
apksigner verify --verbose app-release.apk
署名鍵を紛失し、Play App Signingを使用していない場合、アプリケーションを更新する機能を復元することは不可能です。新しいパッケージ名で新しいアプリケーションを作成する必要があります。これがPlay App Signingを使用する主な理由の1つです。Googleは、keystoreのバックアップコピーを安全なオフラインストレージ(暗号化USBドライブ、銀行の貸金庫)に保管することを推奨しています。
APKをインストールする際、Androidはいくつかの段階で署名検証を実行します。第一に証明書チェック:有効期限が切れていないか、形式が正しいか。第二に署名検証:暗号署名がAPKの内容と一致するか。第三にインストール済みバージョンとの証明書比較:アプリケーションが既にデバイスに存在する場合、証明書が一致しなければならず、そうでなければインストールはブロックされます。
検証システムはPackageManagerServiceに組み込まれています。インストール要求を処理する際、PMSはAPKから署名を抽出し、android.util.PackageParserクラスを使用して検証し、インストール済みアプリケーション(存在する場合)の保存された署名と比較します。一致しない場合、ユーザーは“INSTALL_FAILED_UPDATE_INCOMPATIBLE”エラーを受け取ります。このメカニズムは置き換え攻撃を防ぎます(マルウェアは正当なアプリケーションを自身のバージョンで置き換えることができません)。
開発者は、Android SDK Build Toolsのapksignerユーティリティを使用してAPK署名を独立して検証できます。コマンドapksigner verify --verbose app.apkは、APKがどのスキームで署名されているか、証明書が有効かどうか、署名が内容と一致するかを表示します。インストール済みアプリケーションの署名をプログラムで検証するには、GET_SIGNATURESフラグを指定してPackageManager.getPackageInfo()を使用します。
// インストール済みアプリケーションの署名のプログラムによる検証
fun getAppSignature(context: Context, packageName: String): String? {
val pm = context.packageManager
val info = pm.getPackageInfo(
packageName,
PackageManager.GET_SIGNATURES
)
return info.signatures?.firstOrNull()?.toCharsString()
}
署名鍵のセキュリティはAndroid開発の重要な側面です。鍵の侵害により、攻撃者は自身のコードでアプリケーションの更新に署名できるようになります。主なルール:鍵をリポジトリに保存しない、異なるアプリケーションに同じ鍵を使用しない、安全でないチャネル(電子メール、メッセンジャー)を介して鍵を転送しない。
推奨される実践は鍵の分離です。アプリケーションごとに個別の鍵と、Google Playにアップロードするための個別の鍵(アップロード鍵)を使用します。デバッグビルドの場合、Android Studioは共有のdebug.keystoreを作成します。これはリリースビルドには使用できません。証明書の有効期間は25〜30年であるべきです(現在の標準、Googleによって確認済み)。
| 実践 | 推奨事項 |
|---|---|
| 鍵の保存 | 暗号化メディア、CI/CDシークレット |
| 証明書の有効期間 | 少なくとも25年 |
| アルゴリズム | RSA 2048+またはECDSA P-256 |
| 分離 | アプリケーションごとに個別の鍵 |
| バックアップ | keystoreのオフラインコピー |
定期的に署名チェーンの整合性を確認してください。鍵にアクセスできる従業員が退職した場合は、Google Play Consoleを介してアップロード鍵を更新してください。アプリケーションがユーザーのデバイスで改ざんされていないことを確認するには、Google Play Integrity APIなどのツールを使用してください。APIは署名と整合性に関するデータを返し、検証のためにサーバーに送信します。
よくある質問
Code Signingは、アプリケーションが特定の開発者によって作成され、署名後に変更されていないことを確認するAPKファイルのデジタル署名です。署名がないと、APKはデバイスにインストールされません。
JDKのkeytoolユーティリティを使用します:keytool -genkey -v -keystore my-release.keystore -alias my-alias -keyalg RSA -keysize 2048 -validity 10000。得られたkeystoreをbuild.gradleのsigningConfigsブロックに指定します。
鍵を紛失し、Play App Signingを使用していない場合、アプリケーションの更新は不可能になります。新しいパッケージ名でGoogle Playに新しいアプリケーションを作成する必要があります。鍵の紛失から保護するためにPlay App Signingを使用してください。
v1はAPK内の各ファイルに個別に署名します。攻撃者は1つのファイルを変更し、そのファイルだけに再署名できます。v2はAPK全体にまとめて署名します。変更があると署名が無効になり、より高いレベルのセキュリティを提供します。
Play App Signingは、アプリケーションの配布鍵を集中的に保存するGoogle Playサービスです。開発者はアップロード鍵で署名されたAPKをアップロードし、Googleはユーザーに配信する前に再署名して、鍵の紛失や盗難から保護します。
まとめ
ターンキー方式のモバイルアプリケーションを開発します
IT Sectrは2017年からスタートアップや企業向けにiOS・Androidアプリケーションを開発しています。私たちがご相談に乗り、最適なソリューションをご提案します。