アプリ起動時の安全な接続確立/ブラウザの実装分析

証明書ピンニングは非推奨とされているがそれに代わる手立ては無さそう?
※ 任意の公開鍵を持った証明書はいくらでも作れる。ピンニングするなら公開鍵ではなく証明書。
👇 文責 @ Gemini 2.5 Flash
アプリ起動時の安全な接続確立:信頼の確立方法
ご認識の通り、「アプリ起動時に安全なチャネルを介して」何らかの情報を取得しようとすると、その「安全なチャネル」をどう確立するかという問題に直面しますね。鶏と卵のような状況で、まさにここにセキュリティ設計の難しさがあります。
基本的なHTTPS接続は、CA(認証局)の信頼モデルに基づいています。しかし、このモデルはCAの侵害や不正な証明書発行に対して脆弱です。そのため、より強固な安全性を求める場合、以下のいずれかの方法で「最初の信頼」を確立する必要があります。
1. 事前共有情報の埋め込み(最も推奨されるアプローチ)
これは、サーバーの公開鍵や証明書の情報をアプリのバイナリに直接埋め込んでおく方法です。アプリが起動し、サーバーと接続しようとするときに、この埋め込まれた情報とサーバーから提示された情報を照合することで、そのサーバーが本物であることを確認します。
a. 証明書ピンニング(Certificate Pinning)
- 仕組み: アプリに特定のサーバー証明書(またはその公開鍵、ハッシュ値)をあらかじめ埋め込んでおきます。接続時にサーバーから受け取った証明書が、埋め込まれた情報と一致するかどうかを厳密に検証します。
- なぜ安全か: 中間者攻撃者が不正な証明書を提示しても、アプリがそれを拒否するため、通信が確立されません。これにより、初回接続から信頼できるチャネルを確立できます。
-
種類:
- 公開鍵ピンニング: 証明書に含まれる公開鍵のハッシュ値をピンニングする方法。最も柔軟性があり、推奨されます。証明書が更新されても公開鍵が変わらなければ、アプリの更新は不要です。
- 証明書ピンニング: 証明書そのものをピンニングする方法。証明書が更新されると、アプリも更新する必要があります。管理が煩雑になる可能性があります。
-
注意点:
- サーバーの証明書更新時にアプリのアップデートが必須になる可能性があるため、バックアップ用の公開鍵や、複数の有効期限を持つ証明書をピンニングしておくことが重要です。
- 誤ったピンニング設定は、アプリの通信を完全に妨げる可能性があります。
b. APIキーなどの「シークレット」の埋め込みと保護
- なぜ難しいか: APIキーをアプリに直接埋め込むと、リバースエンジニアリングによって簡単に抽出され、悪用されるリスクがあります。
-
対策(完璧ではないがリスク軽減):
- 難読化 (Obfuscation): コードやデータを意図的に読みにくくすることで、解析を困難にします。これは時間を稼ぐための対策であり、完全に防ぐものではありません。
- 分割と動的組み立て: APIキーを複数に分割し、それぞれを異なる場所に保存したり、実行時にコードで組み立てたりする方法。これも難読化の一種です。
- C/C++での実装: Java/KotlinやSwift/Objective-Cのコードよりも、ネイティブコードの方がリバースエンジニアリングが難しい傾向にあります。
-
OSの安全なストレージの利用:
- iOS: Keychain Services に保存する。これはハードウェアのセキュリティ機能(Secure Enclaveなど)を利用して機密情報を保護します。
- Android: Keystore System に保存する。これもハードウェアバックアップされた鍵ストアを利用して鍵を保護します。
- 注意点: これらのOS提供のストレージも、ルート化されたデバイスやジェイルブレイクされたデバイスでは安全性が低下する可能性があります。
2. 環境への依存と認証連携
デバイスが提供するセキュリティ機能や、外部の信頼できる認証基盤と連携する方法です。
a. デバイス固有の識別子やAttestationの利用(限定的)
- 仕組み: デバイスの固有IDや、デバイスが改ざんされていないことを証明するAttestation情報(例: AndroidのSafetyNet Attestation API、iOSのDeviceCheck API)をサーバーに送信します。
- なぜ安全か: これにより、サーバーはリクエストが「信頼できるデバイス」から来ていることを確認できます。
- 初回接続への寄与: 初回接続時にこれらの情報をサーバーに送り、その応答として安全なチャネル(HTTPS)を通じてAPIキーやトークンを受け取る際に、デバイスの信頼性を追加の要素として利用できます。ただし、このAttestation情報自体が盗聴されないように、何らかの信頼アンカー(上述のピンニングなど)が初期的に必要になります。
b. OAuth 2.0 / OpenID Connect
- 仕組み: ユーザー認証をIdP(Identity Provider)に委譲し、認証が成功するとアクセストークンやIDトークンが発行されます。アプリはこのトークンをサーバーへのリクエストに含めて送信します。
- 初回接続への寄与: ユーザーが既にIdPにログインしている場合、ユーザーの操作を通じて最初の「信頼」が確立されます。トークン自体が通信の安全性を保証するわけではなく、そのトークンを安全にやり取りするためのチャネル(HTTPS + ピンニングなど)が必要です。
- メリット: APIキーをアプリ内に持たなくても、ユーザー認証に基づいてサーバーとのセキュアな通信が可能です。
結論
「アプリ起動時に安全なチャネルを介して」という制約がある場合、最も現実的かつ効果的な方法は、アプリのバイナリにサーバーの公開鍵(またはそのハッシュ)を事前に埋め込む「証明書ピンニング」です。 これにより、アプリがインストールされた時点でサーバーの「指紋」を知っており、初回接続から中間者攻撃のリスクを排除できます。
その上で、APIキーなどの機密情報が必要な場合は、ピンニングされた安全なHTTPSチャネル上でサーバーから取得し、OS提供のセキュアストレージに保管することが望ましいでしょう。
何か他に検討している要素や、制約事項があれば、ぜひ教えてください。それに応じて、より具体的な解決策を検討できます。

Chromeにおける証明書のピンニング
Google Chromeは、かつてウェブサイトが自身の証明書をピン留めするために使用できたHTTP Public Key Pinning (HPKP)
というHTTPヘッダーのサポートを非推奨とし、現在はサポートしていません。HPKPは、不正なデジタル証明書によるなりすまし攻撃を防ぐことを目的としていましたが、運用上の複雑さや、誤った設定によるウェブサイトのアクセス不能化といったリスクがありました。
Google独自のピンニング
しかし、ChromeはGoogle自身のプロパティ(例: google.com
)に対しては、ブラウザのバイナリ内に証明書を埋め込む形で静的な証明書ピンニングを継続しています。これは、Googleが自身のサービスに対するセキュリティをさらに強化するための特別な措置です。
HPKPの代替
HPKPの代替として、GoogleはCertificate Transparency (CT) を推奨しています。CTは、証明書が発行された際にその情報を公開ログに記録する仕組みです。これにより、誤って発行されたり、不正に取得されたりした証明書を早期に検知し、対応することが可能になります。

Safariにおける証明書のピンニング
Google Chromeと同様に、AppleのSafariもウェブサイトがHTTP Public Key Pinning (HPKP)
ヘッダーを使って自身の証明書をピン留めする機能はサポートしていません。多くのブラウザベンダーがHPKPの運用上の複雑さや、誤設定時のリスクを理由に非推奨とし、サポートを終了しています。
Safariにおける証明書のセキュリティ対策
SafariやAppleのプラットフォームでは、HPKPの代替として以下のセキュリティ対策が重視されています。
-
Certificate Transparency (CT):
Appleは、すべての公的に信頼されたTLS/SSLサーバー証明書がAppleのCertificate Transparencyポリシーに準拠することを要求しています。これは、証明書の発行を公開ログに記録することで、誤って発行されたり、不正に取得されたりした証明書を検知しやすくする仕組みです。CTログに記録された証明書にはSCT (Signed Certificate Timestamp) が付与され、SafariはそのSCTを検証することで証明書の信頼性を確認します。 -
静的なピンニング(特定のAppleサービス):
Google Chromeと同様に、Appleも自社の特定のサービス(例えば、iCloudやAppleのウェブサイトなど)に対して、ブラウザやOSのバイナリ内に証明書や公開鍵情報を静的に埋め込む形でピンニングを行っている可能性があります。これは、非常に機密性の高い通信を保護するための特別な措置であり、一般のウェブサイトが利用できる機能ではありません。 -
アプリレベルでのピンニング(開発者向け):
iOS/macOSアプリの開発者は、アプリが特定のサーバーと通信する際に、独自の証明書ピンニングを実装することが可能です。これは、OSレベルやブラウザレベルの機能ではなく、アプリケーション固有のセキュリティ強化策として提供されます。例えば、アプリのInfo.plist
ファイルに公開鍵IDをピン留めすることで、アプリが信頼するサーバー証明書のセットを制限できます。ただし、Apple自身もこの手法は「大半の場合不要」であり、「できるだけその使用を避けるべき」と推奨しています。これは、証明書の更新時にアプリのアップデートが必要になるなど、運用上の手間がかかるためです。
まとめ
- Safariは、一般のウェブサイトが利用するHPKPヘッダーはサポートしていません。
- 主要な代替策としてCertificate Transparency (CT) を厳格に適用しています。
- Apple自身のサービスに対しては、ブラウザ/OSレベルで静的なピンニングを行っている可能性があります。
- アプリ開発者は、自身でアプリレベルのピンニングを実装することも可能ですが、運用上の注意が必要です。
全体として、ブラウザベンダーはHPKPのような複雑なクライアントサイドのピンニングよりも、CTのようにエコシステム全体で証明書の発行を監査する仕組みに移行しています。