前回の非同期プロキシ(メッセージの裏方処理係)の導入で、アプリを閉じても返信が失われなくなりました。でも今は、アプリを開かないと返信が来たかどうか分からない状態です。
LINEやメッセージアプリのように「チバが返信したよ🔔」って通知が来れば、わざわざアプリを開いて確認する必要がなくなります。
プッシュ通知(Push Notification)は、サーバーからスマホに直接メッセージを送る仕組みです。LINEの通知と同じ原理で、アプリを開いていなくても届きます。
Web Push(ウェブプッシュ)という、Webアプリからスマホに通知を送る標準規格を使います。iOS 16.4(2023年3月)から対応しており、ホーム画面に追加したPWA(ウェブアプリ)で利用できます。
通知の暗号化と署名には VAPID(ヴェイピッド:送信元を証明する電子署名の仕組み)という規格を使い、webcrypto-web-push というライブラリで実装します。Cloudflare Workers(サーバー側)で動作する数少ないライブラリです。
通知の暗号化ライブラリを2つ調査しました。通常の web-push というライブラリはNode.js専用で、Cloudflare Workers(サーバー側の実行環境)では動きません。Workers で使える候補を精査した結果です。
正直に記録しておくべきこと:
最初の調査段階で、候補②の webcrypto-web-push は「RFC 8291 準拠の aes128gcm を使用」と評価していました。この情報を根拠に、候補①の PushForge が aesgcm を使っていることを「致命的問題」として不採用にしました。
しかし、ユーザーから「webcrypto-web-push もソースコード監査したの?」と指摘を受け、実際にソースコードを1行ずつ読んだところ、webcrypto-web-push も同じく aesgcm を使っていることが判明しました。
つまり、最初の評価は事実と異なっていたのです。以下は訂正後の正しい評価です。
RFC(アールエフシー)とは、インターネットの技術仕様を定めた公式文書のこと。「こう作りましょう」というルールブックです。
RFC 8291 は「Web Push の通知内容を暗号化する方法」を定めた規格で、aes128gcm(エーイーエス128ジーシーエム)という暗号化方式を推奨しています。
一方、aesgcm は RFC 8291 より前のドラフト(下書き)段階で使われていた方式です。
重要なポイント: 両者の暗号の強さは完全に同じ(どちらも AES-128-GCM という暗号アルゴリズム)。違いはデータの包み方(荷物の梱包方法が違うだけで、中身の安全性は同じ)です。
良い点: ゼロ依存、TypeScript対応、悪意あるコードなし
暗号化方式: aesgcm(候補②と同じ)
不採用理由:
Math.random() を使用。これは暗号用途には不適切な乱数生成器で、予測可能なパターンが生まれる可能性があるソースコード監査結果: 総合評価 B+(本番利用可)
暗号化方式: aesgcm(候補①と同じ)
採用の決め手: 暗号方式は同じなので差別化要因にならない。管理者の信頼性、コード品質、エコシステムの充実度で判断した。
| 項目 | PushForge | webcrypto-web-push |
|---|---|---|
| GitHub スター | 17 | 41 |
| 週間ダウンロード | 1,887 | 4,671 |
| 暗号化方式 | aesgcm | aesgcm(同じ) |
| 管理主体 | 個人(実績なし) | 法人(SG法人・複数OSS運用) |
| コード品質 | B(Math.random等) | B+ |
| Workers実装例 | ドキュメントのみ | リポジトリに実例あり |
| セキュリティ監査 | 悪意なし、品質に懸念 | 悪意なし、品質良好 |
| ライセンス | MIT | MIT |
ここが今回一番ややこしかったところなので、詳しく解説します。
プッシュ通知の中身(「チバが返信したよ」というメッセージ)は、インターネットを通じてスマホに届きます。途中で誰かに盗み見られないよう、暗号化(鍵をかけて中身を読めなくすること)して送ります。
この「鍵のかけ方」には2つのバージョンがあります:
どちらも中身の暗号化には AES-128-GCM(エーイーエス128ジーシーエム)という同じアルゴリズム(計算方式)を使います。つまり「鍵の頑丈さ」は完全に同じです。
違いは3つあります。荷物の配送に例えて説明します:
違い①: 伝票の貼り方(暗号パラメータの伝達方法)
暗号を解くためには「塩」(ソルト:毎回異なるランダム値)や「送り主の公開鍵」が必要です。この情報の伝え方が異なります。
Crypto-Key ヘッダーと Encryption ヘッダーという2枚の伝票に分けて記載違い②: 緩衝材の入れ方(パディングの位置)
「パディング」とは、メッセージの長さを隠すために追加するダミーデータです。短いメッセージ(「OK」など)と長いメッセージ(長文の返信)を同じ長さに見せかけて、盗聴者にメッセージの長さから内容を推測させないためのものです。
違い③: 鍵の作り方の微妙な違い(HKDF の info パラメータ)
暗号鍵を生成する過程で使う「レシピ名」(info文字列)が異なります。aesgcm では "Content-Encoding: aesgcm"、aes128gcm では "Content-Encoding: aes128gcm" という文字列を使います。レシピが違うので生成される鍵も異なりますが、鍵の強度は同じです。料理で例えると、材料は同じでレシピ名が違うだけ。
結論: セキュリティ上の問題はなし。
暗号の強さ(AES-128-GCM)は同一で、上記3つの違いはすべて「データの構造的な差異」です。盗聴や改ざんへの耐性は変わりません。
aes128gcm が「推奨」される理由: セキュリティではなく設計の綺麗さです。暗号パラメータを本体に埋め込む方式(aes128gcm)の方が、別々のヘッダーに分散する方式(aesgcm)より扱いやすく、実装ミスが起きにくい。
現在のサポート状況: 2026年2月時点で、Google (FCM), Apple (APNs), Microsoft (WNS) のすべてのプッシュサービスが aesgcm をサポート中。廃止の予告もなし。
もし将来 aesgcm が廃止されたら?: ライブラリを aes128gcm 対応版に差し替えるだけ。アプリの設計やサーバー構成の変更は不要。影響範囲は小さい。
学んだ教訓: AIの初回調査を鵜呑みにせず、「本当にソースコード読んだの?」と問い直すことが重要。今回はユーザーの指摘がなければ、間違った根拠のまま判断するところでした。
| 種類 | 内容 |
|---|---|
| 新規 4ファイル | 通知送信ロジック、登録API、クライアント購読管理、UIフック |
| 変更 10ファイル | サーバー設定、ルーティング、API引数追加、UI、Service Worker |
| コマンド | VAPID鍵生成、秘密鍵の保存、ライブラリ追加 |
iOS対応: iOS 16.4以降のiPhoneで、ホーム画面に追加したPWAであれば通知が届きます。chibabot-PWAは既にPWA専用設計なので、この条件を自動的に満たしています。
通知の制御: 設定画面のトグルでいつでもON/OFFできます。OFFにすると通知の登録自体を解除するので、バッテリーへの影響もゼロになります。
既存機能との共存: アプリを開いている時はこれまで通りポーリング(定期確認)で回答を表示。バックグラウンド時だけPush通知が活躍します。自然に役割分担されます。
セキュリティ: 通知の内容は暗号化されて送信されます(Web Push標準規格)。VAPIDの秘密鍵はCloudflareのシークレットストレージ(金庫のような安全な場所)に保管され、コードに含まれません。