この文書は2016年以降更新されていません

ピン留めに関するチートシート

OWASP 作成
ジャンプ先: 移動検索
Cheatsheets-header.jpg

最終改訂日 (yy/mm/dd):2015/07/18

はじめに

このピン留めに関するチートシートは、バージニア支部でのプレゼンテーション「Securing Wireless Channels in the Mobile Space (モバイルスペースにおけるワイヤレスチャネルのセキュリティ確保)」で議論された内容を元にした、証明書と公開鍵のピン留めを実装するための技術ガイドです。このガイドは、悪意あるアクターが存在していたり、信頼のカンファレンスが障害となっていたりする危険な環境において、チャネルのセキュリティを確保するための、明快かつ簡潔で実用的なガイダンスを提供することに重点を置いています。

詳細な資料は「Certificate and Public Key Pinning (証明書と公開鍵のピン留め)」にあります。この詳細版には、ピン留めの代替手段、短期鍵、問題点のピン留め、失効、X509 認証などの追加トピックも含まれています。

問題点とは

ユーザー、開発者、およびアプリケーションは、各自のセキュアチャネルにエンドツーエンドのセキュリティを期待しますが、セキュアチャネルの中にはその期待を満たしていないものもあります。特に、VPN、SSL、TLS のような周知のプロトコルを使用して構築されたチャネルは、さまざまな攻撃に対して脆弱です。

ピン留めとは

ピン留めとは、ホストとその望ましい X.509 証明書または公開鍵とを関連付けるプロセスを指します。ホストの証明書または公開鍵が判明したら、その証明書または公開鍵をホストに関連付けます (つまり、ピン留めします)。複数の証明書または公開鍵を許容する場合、プログラムはそれらを集めたピンセット (pinset)を保持します (Jon Larimer 氏と Kenny Root 氏の Google I/O 講演から引用)。この場合、公開されたアイデンティティはピンセット内のいずれかの要素と一致する必要があります。

ホストやサービスの証明書または公開鍵を開発時にアプリケーションに追加することも、証明書または公開鍵に初めて遭遇したときに追加することもできます。前者、つまり開発時に追加する方をお勧めします。証明書または公開鍵をアウトオブバンドプリロードすれば、攻撃者がピンを汚染できないからです。

ピン留めが必要となる条件

リモートホストのアイデンティティを確かめたい場合や、敵対的環境で運用するときにはピン留めを行う必要があります。この条件のどちらかまたは両方にほぼ必ず当てはまるので、おそらくは常にピン留めが必要となります。

ホワイトリスト化するタイミング

データ損失防止 (DLP) 戦略の一環として "出口フィルタリング" を行っている組織に勤務する場合、透過型プロキシ (Interception Proxy)に出会う可能性が高くなります。このようなプロキシを ("悪い" 悪党に対して) "良い" 悪党と呼ぶことにします。どちらもエンドツーエンドのセキュリティを破り、区別が付かないからです。この場合、セキュリティ目標を挫くことになるため、インターセプションプロキシのホワイトリスト化を提案しないでください。リスク許容部門の同僚からそうするよう指示されたら初めて、インターセプションプロキシの公開鍵をピンセットに追加してください。

ピン留めの実装方法

考え方としては、既存のプロトコルとインフラストラクチャを再利用し、さらに防御を強化します。まず最初に、プログラムで安全な接続を確立する際に従来行っていたのと同じ処理を実行します。

そしてチャネルの防御を強化するために、ライブラリ、フレームワーク、またはプラットフォームが提供する OnConnect コールバックを活用します。このコールバック内で、リモートホストの証明書または公開鍵を検証することで、そのアイデンティティを確認します。

ピン留めの対象

まず決めなければならないのは、何をピン留めするかです。これには次の 2 つの選択肢があります。(1) 証明書をピン留めする、(2) 公開鍵をピン留めする。公開鍵を選んだ場合、さらに 2 つの選択肢があります。(a) subjectPublicKeyInfo をピン留めする、(b) RSAPublicKeyDSAPublicKey など具体的な種類の 1 つをピン留めする。

subjectPublicKeyInfo
この 3 つの選択肢について、以下で詳しく説明します。個人的には、 subjectPublicKeyInfo をピン留めすることをお勧めします。この公開鍵には公開パラメーター (RSA 公開鍵の {e,n} など) コンテキスト情報 (アルゴリズムや OID など) が含まれているからです。コンテキスト情報は、通信を維持するために役立ちます。右の図にその他の入手可能な情報を示します。

証明書

証明書
最もピン留めしやすいのは証明書です。Web サイトの証明書をアウトオブバンドで取得できるほか、IT 部門に頼んで自社の証明書を電子メールで送ってもらったり、 openssl s_client を使用して証明書を取得したりできます。コールバック内で、取得した証明書をプログラムに埋め込まれている証明書と照合します。照合に失敗した場合は、そのメソッドまたは関数をエラー終了させます。

証明書のピン留めにはマイナス面もあります。サイトが証明書を定期的にローテーションしている場合は、アプリケーションを定期的に更新することが必要になります。たとえば、Google では証明書をローテーションしています。したがって、アプリケーションが Google サービスに依存している場合は、アプリケーションを毎月 1 回更新する必要があります。Google が証明書をローテーションしても、証明書内の基となる公開鍵は静的なまま変わりません。

公開鍵

公開鍵
公開鍵のピン留めはより柔軟性がありますが、証明書から公開鍵を抽出するために余分な手順が必要になります。証明書の場合と同様に、プログラムでは抽出した公開鍵をプログラムに埋め込まれている公開鍵のコピーと照合します。

公開鍵のピン留めには 2 つの欠点があります。第一に、証明書から公開鍵を抽出しなければなりません。公開鍵の抽出は、Java や .Net ではさほどの不都合はありませんが、Cocoa/CocoaTouch や OpenSSL では厄介です。第二に、鍵が静的であり、鍵のローテーションポリシーに違反する可能性があります。

ハッシュ化

上の 3 つの方法では DER エンコードされた鍵情報自体を使用しましたが、鍵情報のハッシュ値を使用することも可能です。実際に、最初のサンプルプログラムはダイジェスト化された証明書と公開鍵を使用して記述されました。その後、サンプルプログラムが変更され、プログラマーが dumpasn1 やその他の ASN.1 デコーダーのようなツールを使用してオブジェクトを検査できるようになりました。

ハッシュ化には、3 つの追加メリットがあります。第一に、ハッシュ化すると証明書または公開鍵を匿名化できます。アプリケーションが逆コンパイルやリバースエンジニアリングされることで情報漏えいが懸念される場合には、これが重要になるかもしれません。第二に、ダイジェスト化された証明書のフィンガープリントが、たいていの場合、多くのライブラリでネイティブ API として利用できます。

最後に、組織では第一のアイデンティティが危殆化した場合に予備のアイデンティティを供給したいことがあります。ハッシュ化すれば、予備の証明書または公開鍵がその使用前に敵対者の目に触れないことを確保できます。現に、Google の IETF ドラフト websec-key-pinning ではこの手法が採用されています。

ピン留めの例

ここでは、Android Java、iOS、.Net、および OpenSSL での証明書と公開鍵のピン留めについて説明します。説明を簡単にするためコードは割愛し、各プラットフォームにおけるキーポイントを強調します。どのプログラムも random.org に接続してバイトデータを取得することを試みます (Dr. Mads Haahr が AOSP ピン留めプログラムに参加したので、このサイトには静的な鍵があるはずです)。各プログラムは、同サイトについてすでに知っている (より正確には、先験的な知識を持っている) ものとします。したがって、サイトの公開鍵のコピーを組み込み、公開鍵をピン留めします。

Android

Android でのピン留めは、 X509TrustManager をカスタマイズすることによって実現します。 X509TrustManager は、通常の X509 チェックに加え、ピン留めされた公開鍵のチェックを行います。

ダウンロード: Android 用サンプルプログラム

iOS

iOS でのピン留めは、 NSURLConnectionDelegate を通じて行います。デリゲートが connection:canAuthenticateAgainstProtectionSpace: および connection:didReceiveAuthenticationChallenge: を実装する必要があります。デリゲートは connection:didReceiveAuthenticationChallenge: の中で SecTrustEvaluate を呼び出して通常の X509 チェックを実行します。

ダウンロード: iOS 用サンプルプログラム

.Net

.Net でのピン留めは ServicePointManager を使用して実現できます。

ダウンロード: .Net 用サンプルプログラム

OpenSSL

OpenSSL では、2 箇所でピン留めを行うことができます。1 つ目は、ユーザー定義の verify_callback です。もう 1つは、 SSL_get_peer_certificate によって接続を確立した後です。どちらのメソッドでも通信相手の証明書にアクセスできます。

OpenSSL が X509 チェックを行いますが、エラー時にはアプリケーションが明示的に接続を終了してソケットを閉じる必要があります。設計上、証明書を提供しないサーバーの結果は X509_V_OK となり、NULL の証明書が返されます。したがって、通常の検証の結果を確認するには、(1) SSL_get_verify_result を呼び出し、戻りコードが X509_V_OK であることを確認し、次に (2) SSL_get_peer_certificate を呼び出して、証明書が NULL 以外であることを確認します。

ダウンロード: OpenSSL 用サンプルプログラム


参考資料

Authors and Editors

  • Jeffrey Walton - jeffrey, owasp.org
  • John Steven - john, owasp.org
  • Jim Manico - jim, owasp.org
  • Kevin Wall - kevin, owasp.org

Other Cheatsheets

Developer Cheat Sheets (Builder)

Assessment Cheat Sheets (Breaker)

Mobile Cheat Sheets

OpSec Cheat Sheets (Defender)

Draft Cheat Sheets