設計の背景/ Why This Design
この仕組みが引き受けた課題と、そこから決まった構成
共有リンクは「アカウントを持たない相手に、こちらのファイルを渡す」という、アプリの中で最も外に開いた機能です。開いた分だけ設計の制約も強くなります。ここでは、何を解決するために作ったのか、なぜ受取ページを本体と別のホストに置いたのか、そしてログインという手がかりが無いまま何を積み上げたのかをご説明します。
解決する業務課題The Problem
取引先とのやりとりには、継続的なものと単発のものがあります。継続的なものは Box に招待して共同で扱えばよいのですが、「この 1 件を渡すだけ」に同じ手間はかけられません。かといってメールに添付すると、渡したあとの制御が一切効かなくなります。
| 観点 | メール添付 | Box へ招待 | 共有リンク |
|---|---|---|---|
| 相手の準備 | 不要 | アカウント作成と招待の受諾が必要 | 不要(URL を開くだけ) |
| 扱えるサイズ | 数 MB 程度で弾かれる | アップロードの上限まで | アップロードの上限まで(フォルダは ZIP のしきい値あり) |
| 渡したあとの取り消し | できない | メンバーから外せる | いつでも無効化できる |
| 期限 | なし(相手の受信箱に残り続ける) | なし | 最長 14 日で自動的に開かなくなる |
| 受け取りの確認 | できない | 操作履歴で分かる | 開封とダウンロードが記録される |
| ウイルス検査 | 相手のメール環境まかせ | 取り込み時に検査済み | 検査済みのファイルしか渡せない |
共有リンクは、この表のいちばん右の列を実現するための機能です。相手には手間をかけず、こちら側は「いつまで・何回・誰に・どこまで」を握ったまま渡す。渡したあとに気が変わったら止められる。これが引き受けた課題です。
公開ホストの分離The Public Host
受取ページは、本体アプリ portal.example.com ではなく inbox.portal.example.com という別のホスト名で公開しています。同じアプリの一部でありながらホストを分けたのは、次の 3 つを同時に成立させるためです。
| 分けて得られること | 内容 |
|---|---|
| Cookie の分離 | ブラウザの Cookie はホスト名で区切られます。ホストを分ければ、社員のログインセッションの Cookie が公開面へ構造的に出ていきません。受取ページが使う Cookie も、その受取ページ専用の短命なものだけになります。 |
| 防御設定の独立 | 公開面は本体より攻撃を受けやすいため、上限を厳しくしたい一方で、社員の通常業務を巻き込みたくありません。ホストが分かれていれば、Cloud Armor のルールもレート制限も公開面だけに強くかけられます(公開面は本体より厳しい IP ごとのレート制限にしています)。 |
| 公開する経路の限定 | 共有リンクのために公開ホストへ通しているのは /s/{token}(受取ページ)と /api/share-links/*(状態確認・照合・URL 発行)の2 経路だけです。本体 API 全体は、このホストからは到達できません。 |
分けた分だけ構成が増えるかというと、そうではありません。DNS は同じゾーンで管理し、負荷分散は 1 台のロードバランサがホスト名を見て振り分けます。証明書も 2 ホスト分を 1 枚にまとめた Google マネージド SSL です。増えるのは「ルール」だけで、運用する部品は増やしていません。
アカウント不要の受け渡しAccess Without Accounts
受け取る側はログインしていません。つまり「誰が来ているか」をアカウントで判断できないまま、正しい相手には確実に渡し、それ以外には渡さない必要があります。この矛盾は、1 つの強い仕掛けではなく、性質の違う手がかりを重ねることで解いています。
| 手がかり | 何を確かめているか | 単独では足りない理由 |
|---|---|---|
| 推測できない URL | その URL を知っていること | 転送されれば誰でも知りうる |
| パスワード | URL とは別の経路で伝えた合図を知っていること | URL と一緒に伝えてしまえば意味がない(だからシステムからは送らない) |
| 受取人の本人確認 | 指定したメールアドレスを受信できること | そのメールボックスを見られる人には通る |
| 有効期限 | 渡してからの経過時間 | 期限内であれば止まらない |
| ダウンロード回数 | 受け取られた回数 | 回数内であれば止まらない |
| レート制限とロック | 試行の速さと失敗の多さ | 正しい合図を知っている相手は止められない |
どれも単独では破れます。しかし破り方が互いに違うため、重ねると全部を同時に満たす必要が生まれます。URL を手に入れただけでは開けず、パスワードを推測しようにも速さで止められ、時間をかけようにも期限が来る。この「手口の異なるものを重ねる」考え方が、この機能全体の背骨です。実装の詳細は防御の設計で扱います。
設計の四原則Design Principles
個々の判断で迷ったときに立ち返っている 4 つの原則です。この先の各ページで出てくる「一見まわりくどい作り」は、たいていこのどれかに由来しています。
1. 検査済みのものだけを渡す
共有リンクで渡せるのは、ウイルス検査を通過(検査済み)したファイルだけです。検査中・検査に失敗・隔離されたファイルは、発行時に対象として選べないだけでなく、データベースの読み取り範囲そのものから外れています。発行後にファイルが差し替えられた場合も、受取人に見えるのは検査済みの最新版だけです。
2. 失効は不可逆、編集はさせない
発行したリンクはあとから編集できません。期限を延ばす、回数を増やす、受取人のメールアドレスを変える、いずれも用意していません。条件を変えたいときは、無効化して発行し直します。無効化も取り消せません。
これは画面でボタンを出していないだけではありません。ログインした利用者がデータベースに対して書き換えられるのは「無効化した日時」と「無効化した人」の2 つの列だけで、期限や回数の列は権限そのものが与えられていません。仮にアプリ側に穴があっても、条件の書き換えはデータベースが拒みます。
3. 記録は必ず残す
受取ページで起きたことは、成功も失敗もすべて記録します。開封(受取画面に着いた)・ダウンロード・パスワードの誤り・確認コードの誤り・期限切れ後のアクセス・無効化後のアクセス・回数上限・アクセス集中による制限、そして存在しないリンクへのアクセス。記録しているからこそ異常を自動で見つけられます(記録と異常検知)。
4. 止める手段を常に用意する
止められる人を 3 層に用意しています。発行者本人と Box の Owner はいつでも無効化でき、全社の管理者は発行者の意向に関わらず強制的に失効させられます。加えて、元のファイルやフォルダを削除したとき、Box を無効化したときには、それを指す共有リンクが自動的に無効になります(管理機能)。