APNsを利用する際に必要な2種類の接続信頼について
APNsを利用する際に必要な2種類の接続信頼
APNsを利用する際には証明書やトークンが必要ですが、それは認証のためです。
ドキュメント*1には、暗号化されたデータが正しく復号できるか、途中で改ざんされていないかみたいな確認にあたる暗号化検証とあわせて 接続信頼 と呼ばれています。
この接続信頼には
- プロバイダ - APNs間の接続信頼
- APNSにリクエストを送ってきた人がプロバイダー(=プッシュ送りたい人、アプリ作った人)であることを証明する
- これが確認できないと、プロバイダとAPNsの間でやりとりはできない
- APNs - デバイス間の接続信頼
- APNsから通知を受信するデバイスが、認証を受けたもののみであることを証明するためのもの
の2種類があります。
プロバイダーAPNs間の接続信頼
まず、プロバイダーAPNs間の接続信頼の話をします。
プロバイダーAPNs間の接続信頼には「トークンベースのプロバイダ接続信頼」「証明書ベースのプロバイダ接続信頼」があり、それぞれ接続信頼を確認するために必要な手順やプロバイダのサーバに配置するファイルが異なります。
トークンベースのプロバイダ接続信頼
- WWDC2016で公表された方式。
- こちらの記事の手順で管理画面で Apple Push Notification Authentication Key(Sandbox & Production) を発行し、その際にダウンロードする
.p8
ファイルをサーバーに配置Apple Push Notification Authentication Key
の 有効期限は無期限 です(こちらの操作により無効にすることも可能)
- こちらの記事 に書いてあるような手順で
.p8
ファイルから秘密鍵を取り出し、時刻を利用して認証に使うトークンを生成します - バンドルIDが記載されているすべてのアプリケーションにおいて同じ
Apple Push Notification Authentication Key
を使うことが可能です - 余談として、ドキュメントの セキュリティアーキテクチャ > プロバイダ-APNs間の接続信頼 > トークンベースのプロバイダ接続信頼に
鍵ペアを生成し、公開鍵をAppleに渡してください。秘密鍵はプロバイダ側で保持し
と書いてあるものの、公開鍵をどうこうした覚えはなくて若干戸惑っていたり。。- これは推測ですが、秘密鍵がそのときDLする
.p8
ファイルに入っているので、多分公開鍵はApple Push Notification Authentication Key
を発行した時にAPNs側に保管されているのでしょう。。
- これは推測ですが、秘密鍵がそのときDLする
トークンベースの接続信頼を利用する場合に送るリクエストの例
HEADERS - END_STREAM + END_HEADERS :method = POST :scheme = https :path = /3/device/00fc13adff785122b4ad28809a3420982341241421348097878e577c991de8f0 host = api.development.push.apple.com authorization = bearer eyAia2lkIjogIjhZTDNHM1JSWDciIH0.eyAiaXNzIjogIkM4Nk5WOUpYM0QiLCAiaWF0I jogIjE0NTkxNDM1ODA2NTAiIH0.MEYCIQDzqyahmH1rz1s-LFNkylXEa2lZ_aOCX4daxxTZkVEGzwIhALvkClnx5m5eAT6 Lxw7LZtEQcH6JENhJTMArwLf3sXwi apns-id = eabeae54-14a8-11e5-b60b-1697f925ec7b apns-expiration = 0 apns-priority = 10 apns-topic = <MyAppTopic> DATA + END_STREAM { "aps" : { "alert" : "Hello" } }
- ヘッダーに接続信頼用の
authorization
キーがあります。 Apple Push Notification Authentication Key
は開発者アカウントと紐付いているすべてのアプリと紐付いているので、どのアプリ宛かを指定するためのapns-topic
の指定があります。- デバイストークンの指定は、
:path
で行われています。
証明書ベースのプロバイダ接続信頼
- 証明書ベースのプロバイダ接続は、プロバイダ証明書(具体的には .p12 ファイルや .pem の中に含まれているデータ)で指定されている特定の1つのアプリケーションのためのものです
- 接続信頼の確認に利用する証明書は事前に作成します
- 証明書ベースの信頼を利用する場合、APNsが証明書失効リストを作成、管理しています*4
- 証明書ベースでプロバイダ接続信頼を行う場合、証明書を使うのはTLS接続確立までで、個々のリモート通知リクエストの時は通知先のデバイストークンだけヘッダにつければよいです
- トークンベースの接続信頼で使う
Apple Push Notification Authentication Key
と違い、証明書ベースの接続信頼で使うSSL証明書(.p12ファイル)は1年の有効期限があります
証明書ベースの接続信頼を利用する場合に送るリクエストの例
HEADERS - END_STREAM + END_HEADERS :method = POST :scheme = https :path = /3/device/00fc13adff785122b4ad28809a3420982341241421348097878e577c991de8f0 host = api.development.push.apple.com apns-id = eabeae54-14a8-11e5-b60b-1697f925ec7b apns-expiration = 0 apns-priority = 10 DATA + END_STREAM { "aps" : { "alert" : "Hello" } }
- トークンベースの場合と違い、
authorization
キーはありません。 - 基本的に、証明書ベースの場合、証明書の中にどのアプリ用の証明書か含まれているため、証明書の中に記載されたトピックへのリクエストとして処理できるため、
apns-topic
の指定がありません- 複数のtopic用の証明書の場合は
apns-topic
の指定が必要です。
- 複数のtopic用の証明書の場合は
- デバイストークンの指定は、
:path
で行われています。
APNs-デバイス間の接続信頼
次にAPNs - デバイス間の接続信頼の話をします。
大枠を言うと
- iOSなどのデバイスの利用開始設定(アクティベーション時)に接続信頼に利用される暗号化証明書と秘密鍵がOSから提供される
- OSから提供された暗号化証明書と秘密鍵はキーチェーンに格納され、アプリケーションとは関係なしにAPNsとデバイスとの間の接続信頼に利用される
- (= デバイスとAPNsとの接続信頼のために、開発者がなにかする必要はない)
となります。
そうすると自分(プロバイダ)として関心があることは、このAPNs - デバイスが接続された上で、デバイスへのリモート通知リクエストに必要なトークンを取得することですが、この部分については開発者側で実装や設定が必要です。
iOSおよびtvOSでのデバイストークンの取得などを参考にアプリケーションがリモート通知リクエストを送るためにAPNsへリクエストを送り、結果を受け取る実装をし、また、Enable push notificationsを参考にアプリケーションがプッシュ通知を利用する設定が必要です。
参考
- Apple Push Notification サービス
- リモート通知サポートの設定
- Enable push notifications
- Golangで「プロバイダー認証トークン」を生成して、APNsにプッシュを送ろう
- Apple Push Notification Authentication Keyを発行しよう
*1:https://developer.apple.com/jp/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/APNSOverview.html#//apple_ref/doc/uid/TP40008194-CH8-SW1
*2:かといって接続のたびに再発行してほしいわけではない
*3:アプリのリモート通知以外にもVoIP通知などの用途があり、その場合アプリのbundle IDに .voip がついた値をtopicに指定する https://developer.apple.com/jp/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/CommunicatingwithAPNs.html#//apple_ref/doc/uid/TP40008194-CH11-SW1
*4:これは、開発している時にはPush屋さんが失効時の挙動テストする時にAPNsのサンドボックスでの失効が遅い...(なんかSANDBOXの場合、半日くらい待ってる気がする) というくらいしか縁がないのではないか...