情報セキュリティ担当者・アプリ審査担当者の方へ
Peel のセキュリティ
要点:ボードの内容は、リンクのフラグメントにある鍵を使ってブラウザ内で暗号化されます。そのため、私たちのサーバーが保存・中継するのは読むことのできない暗号文だけです。以下で、その具体的なしくみと限界を説明します。
概要
- カードの内容、名前、ボードのタイトル、投票、ステッカーは、ブラウザで生成したボード鍵を使い AES-256-GCM で暗号化されます。鍵は URL のフラグメント(
#k=)で受け渡され、サーバーには送信されません。 - ファシリテーターの操作、ボードのヘッダー、スナップショットは、ファシリテーターの Ed25519 鍵で署名されます。ボード ID はこの鍵から導出されるため、鍵のすり替えはクライアントが検出します。
- 非表示のカードは公開までファシリテーター宛てに封印(X25519 sealed box)され、ソルト付きコミットメントで束縛されるため、公開時に内容をすり替えることはできません。
- 初期設定は匿名:操作には投稿者 ID が含まれず、投票とリアクションにはボードごとのランダム ID が使われます。
- 参加者は認証を行いません。アナリティクス SDK、広告、サードパーティのスクリプトは使用しません(チェックアウトページの Paddle.js を除く)。
- Cloudflare のみを使用。所有者のいないボードは、最後のアクセスから60日で削除されます。
データの流れ
URL のフラグメント(# 以降のすべて)はブラウザ内で処理され、HTTP リクエストには含まれません。Peel はここにボード鍵を置いています。
脅威モデル
サーバーが完全に侵害されたり、好奇心を持ったりした場合でも(私たち自身を含め)、チームの発言内容についてできるかぎり何もわからないように設計しています。
保護するもの
- カードの内容、選ばれた GIF、記名モードでは投稿者の名前。
- 参加者の名前とアバター、ボード名、カスタムテンプレートのタイトル。
- 誰が何に投票・リアクションしたか、誰がどのカードを書いたか。
- ふりかえりの完全性:ステップ、公開、ファシリテーターの決定は偽造できません。
想定する攻撃者
- 私たち自身のサーバー、悪意のある内部関係者、ストレージへの侵入者:得られるのは暗号文とメタデータだけです。
- ネットワーク上の攻撃者:すべて TLS で通信し、鍵がネットワークを通ることはありません。
- 鍵をすり替えるサーバー:ボード ID はファシリテーターの公開鍵から導出され、クライアントは署名済みヘッダーを検証します。
- のぞき見や偽造をしたい参加者:非表示のカードはファシリテーター宛てに封印され、ファシリテーターの操作にはその署名が、カードの編集にはそのカードの鍵が必要です。
- オフラインの投稿者に代わって再公開するファシリテーター:コミットメントにより内容は変更できません。
対象外(正直に言うと)
- 参加者用リンクを持っている人は誰でもボードを読めます。リンクそのものがアクセス制御です。ボードと同じように扱って共有してください。
- 侵害された端末、悪意のあるブラウザ拡張機能、肩越しにのぞき見る人。
- トラフィック分析:サーバーにはタイミング、サイズ、件数が見えます(データマップ参照)。
- サーバーによるサービス妨害:メッセージを破棄・遅延させることはできますが、読んだり偽造したりはできません。
暗号技術
すべての暗号プリミティブはブラウザの WebCrypto API を使用しています。独自の暗号も、サードパーティの暗号ライブラリも使いません。
| 鍵 | アルゴリズム | 用途 |
|---|---|---|
| K_board | AES-256-GCM、96ビットのランダム IV | すべての操作、スナップショット、プレゼンス更新を暗号化します。追加データでボード ID・操作の種類・操作 ID を束縛するため、暗号文を別のボードや位置に再利用することはできません。リンクのフラグメント #k= にのみ存在します。 |
| K_owner | Ed25519 | ファシリテーターの権限です。ファシリテーターの操作(ステップ、タイマー、スポットライト、テンプレート、設定、投票の公開、カードの非表示)、ボードのヘッダー、スナップショットに署名します。単調増加するカウンターでリプレイを防ぎます。ファシリテーター用リンク(&o=)にのみ含まれます。 |
| ボード ID | SHA-256 の先頭80ビット、base32 | ファシリテーターの公開鍵から導出されるため、ID そのものがどの鍵がボードを所有しているかを証明します。鍵のハッシュが ID と一致しないヘッダーは、クライアントが拒否します。 |
| K_fac | X25519 sealed box:エフェメラル X25519 + HKDF-SHA256 + AES-256-GCM | 記入中の非表示カードは、ファシリテーターの公開鍵宛てに封印されます。開けるのはファシリテーター用リンク(&f=)だけです。 |
| カード鍵 | Ed25519、カードごとに1つ | 投稿者だけが保持します。編集と公開はこの鍵で署名されます。身元を明かさずに真正性を保証します。 |
| コミットメント | HMAC-SHA256、128ビットのランダムソルト | 非表示のカードは内容へのコミットメントを公開します。公開時に内容とソルトが公開され、すべてのクライアントが照合するため、誰も内容をすり替えられません。 |
| プレゼンス | K_board による AES-256-GCM | 名前、アバター、入力中の表示も、ほかのすべてと同じく暗号化されます。 |
| 鍵バンドル | パスキーの PRF またはリカバリーコードから HKDF-SHA256、AES-256-GCM | ログインしたファシリテーターは、ボードの鍵を端末間で同期できます。バンドルは端末上で暗号化され、サーバーが保存するのは暗号文とラップされた鍵だけです。 |
署名対象のメッセージはドメイン分離されています(例:peel/sig/v1、peel/header/v1、peel/snap/v1)。ある目的の署名を別の目的に流用することはできません。
匿名性
- 操作には投稿者 ID が含まれません。サーバーはカードと人物を結びつけられず、初期設定ではファシリテーターにもできません。
- 投票とリアクションは、名前と結びつかないボードごとのランダム ID で管理されます。
- 入力中の表示は、誰かが書いていることだけを示し、何を書いているかは示しません。
- 記名モードはボードの明示的な設定です。その場合、投稿者の名前は暗号化されたカードの中で送られます。
- 参加者はログインしないため、照合できるアカウントそのものが存在しません。
データマップ
私たちが保持するすべてのデータ、その保存場所、読める人、保存期間。
| データ | 保存場所 | 読める人 | 保存期間 |
|---|---|---|---|
| カード、投票、リアクション、ステッカー、アクション、ボード名、カスタムテンプレートのタイトル | Durable Object のストレージ(暗号文) | ボードのリンクを持っている人 | ボードが削除されるまで |
| 操作のエンベロープ:種類、サーバーの連番と時刻、サイズ、ファシリテーターのカウンター | Durable Object のストレージ | Peel | ボードが削除されるまで |
| 参加者の名前、アバター、入力中の表示 | 暗号文として中継。接続中のみメモリに保持 | ボードのリンクを持っている人 | 接続中のみ |
| ボードのステータス:ステップ、参加者数とカード数、カタログのテンプレート ID、ロックの有無、作成日時と有効期限 | Durable Object、D1。インストール済みなら Slack/Teams のメッセージ | Peel、あなたの Slack/Teams チャンネル | ボードの存続期間 |
| ファシリテーターのアカウント:プロバイダー ID、名前、共有された場合はメールアドレス、連携プロバイダー、作成日、セッション | D1 | Peel | アカウントを削除するまで |
| 鍵バンドルとラップされた鍵 | D1(暗号文) | あなただけ(パスキーまたはリカバリーコード) | アカウントを削除するまで |
| プラン、サブスクリプションの状態、Paddle の顧客 ID とサブスクリプション ID | D1、Paddle | Peel、Paddle | 税法で定められた期間 |
| Slack/Teams のワークスペース・チャンネル・メッセージの ID、ボットトークン(AES-GCM で暗号化) | D1 | Peel | アンインストールされるまで |
| IP アドレス | Cloudflare のエッジで一時的に(配信、レート制限) | Cloudflare、Peel のレート制限機能 | データベースには保存しません |
| 日次カウンター(作成されたボード数、到達したステップ) | D1 | Peel | 集計値のみ、識別子なし |
サーバーにできること、できないこと
できること
- 操作の種類、サイズ、タイミング、ステップ、参加者数とカード数、カタログのテンプレート ID、ロックの有無を見ること。
- 操作を破棄・遅延したり、配信を拒否したりすること(サービス妨害)。
- ネットワークのエッジで IP アドレスを見ること。
- 作成されたボード数と到達したステップを集計で数えること。
- ボードを削除すること(有効期限切れ、不正利用の報告)。
できないこと
- カードの内容、名前、ボードのタイトル、カスタムテンプレートのタイトル、投票、ステッカーを読むこと。
- 公開前の非表示カードを読むこと(公開後でさえ読めません)。
- ファシリテーターの操作を偽造すること:ファシリテーターの署名が必要です。
- 自分の鍵にすり替えること:ボード ID で見破られます。
- 公開されたカードの内容を変えること:コミットメントとカードの署名で見破られます。
- 誰がどのカードを書いたかを知ること。
ほかの Web アプリと同様、私たちが配信するコードは信頼していただく必要があります。その範囲を小さく保つため、厳格な Content Security Policy を適用し、script-src を自分たちのオリジンに限定し、サードパーティのスクリプトは使わず、プロトコルはご要望に応じてレビューいただけます。
Slack と Microsoft Teams
- メッセージに含まれるのはボードのリンクとメタデータ(タイトル、ステップ、件数)だけです。カードの内容は、ファシリテーターがサマリーを投稿して確認したときにだけ送られます。
- 参加カードには鍵を含む参加者用リンクが入っています。そのチャンネルを読める人は誰でも参加できます。リンクを貼るのと同じです。
- リンクの展開(unfurl)に表示されるのはステップと件数だけで、内容は表示されません。
- Slack のスコープ:
commands、chat:write、links:read、links:write。users:readはチームがメンションを有効にした場合のみ。 - ボットトークンは保存時に暗号化されます(AES-GCM、鍵は Worker のシークレットとして保持)。Slack のリクエスト署名と Bot Framework のトークンは、すべてのリクエストで検証します。
- アプリをアンインストールすると、すべての投稿が止まり、トークンは削除されます。
Web とインフラ
- Cloudflare のみ:1801 Labs アカウント上の Pages、Workers、Durable Objects、D1、R2、KV。ほかのサーバーはありません。
- すべて TLS、HSTS、厳格な Content Security Policy。
- アナリティクス SDK、広告、サードパーティのスクリプトはなし。唯一の例外は Paddle.js で、チェックアウトページでのみ読み込みます。
- Cookie はログインしたファシリテーター向けの1つだけ:
peel_session(httpOnly、Secure、SameSite=Lax)。 - GIF 検索とメディアは私たちの API を経由するため、参加者の IP アドレスが GIPHY に届くことはありません。
- フォントとアセットはセルフホスト。CDN フォントもトラッキングピクセルもありません。
- IP ごと・ボードごとのレート制限、不正利用の報告、ファシリテーターによるロック。
アカウントと保存期間
- 参加者は認証を行いません。ファシリテーターが Google(Teams 経由なら Entra ID)でログインするのは、ボードを残したいときや有料機能を使うときだけです。
- アカウントに保存されるのは、ID、プロバイダーから受け取った名前とメールアドレス、そしてパスキー(WebAuthn PRF)かリカバリーコードでロック解除する暗号化された鍵バンドルです。ログインで得られるのは所有権であって、内容へのアクセスではありません。
- ボードの所有はファシリテーターの署名で証明します。ボードの鍵が送られることはありません。
- アカウントなしのボードは、最後のアクセスから60日で削除されます。アクセスするたびにカウントはリセットされます。ストレージは Durable Object のアラームで削除されます。
- アカウントを削除すると、セッション、鍵バンドル、ライブラリが削除され、ボードには再び60日の有効期限が適用されます。
責任ある開示
問題を見つけましたか? まずは私たちにお知らせください。一緒に対応します。報告は3営業日以内に受領確認します。
- 公表の前に、修正のための妥当な期間(目安は90日)をお待ちください。
- テストはご自身のボードとアカウントで行ってください。他人のデータにアクセスしたり、サービスを低下させたりしないでください。
- これらのルールに従った善意の調査に対して、法的措置をとることはありません。
- 機械可読な連絡先:
/.well-known/security.txt。
Company プランのお客さまには、セキュリティ審査パック(質問票への回答、サブプロセッサー、データフロー)をご用意しています。 DPA · プライバシー