リンクの発行/ Issuing a Link
何を確かめ、何を決め、何を保存し、どう届けるか
共有リンクを 1 本作る操作は、画面の上では「対象を選んで条件を決めて発行を押す」だけです。その裏では、対象が本当に渡してよいものかを検査し、推測できない URL を作り、パスワードを取り出せない形に変換し、案内メールを取りこぼさず配送するための段取りを組んでいます。ここではその中身を順に開きます。
発行の流れIssue Flow
上段が業務としての流れ、下段がそれを実現している技術としての処理です。上下は同じ位置で対応しています。発行できるのは、その Box の Editor または Owner だけです。
上段と下段は破線で対応しています。下段の右端「送信予定を積む」から先は、この後の「案内メールの配送」で扱います。
対象の検証Target Validation
発行の入口で、対象が本当に渡してよいものかを確かめます。ここを通らないものは、そもそもリンクを作れません。
| 確かめること | ファイルのとき | フォルダのとき |
|---|---|---|
| Box への所属 | 操作している Box に属していること(別の Box のものは指定できません) | |
| 削除されていない | 論理削除されていないこと | |
| ウイルス検査 | 最新版が検査済みであること | 配下に検査済みのファイルが1 件以上あること(0 件では発行できません) |
| アーカイブ配下でない | 対象自身、または祖先フォルダのいずれかがアーカイブされていないこと | |
アーカイブは「読み取り専用に凍結した」状態なので、新しく共有リンクを発行することだけを止めます。すでに発行済みのリンクは生き続けますし、無効化はいつでもできます。凍結したものから新たな外部露出が生まれないようにしつつ、既に相手が受け取り待ちのものを勝手に切らない、という切り分けです。
設定項目と既定値Settings
設定できるのは 5 項目です。ダイアログは「そのまま発行してよい状態」で開きます。詳細設定は開いた状態で、パスワードは自動生成済み、回数は 3 回、案内メールは送る、が既定です。
| 項目 | 選べる値 | 既定 | サーバ側の制約 |
|---|---|---|---|
| 有効期限 | 24 時間 / 7 日 / 14 日 / 日付を指定(選んだ日の 23:59 まで) | 7 日 | 上限 14 日。運用中に上限を短くでき、超えるプリセットは選択肢から消えます(押せるのにエラーになる状態を作らない) |
| パスワード | 設定する / しない | 設定する | 8〜100 文字。既定では開いた時点で 12 文字を自動生成(英大小文字と数字・見分けにくい字は使わない) |
| ダウンロード回数 | 無制限 / 1 回のみ / 回数を指定(1〜100) | 3 回 | ZIP のしきい値を超えるフォルダのときだけ既定が無制限になります(下の注記) |
| 受取人の本人確認 | する(メールアドレス 1 件)/ しない | しない | 指定したアドレス宛の 6 桁コードで確認します。あとから変更できません |
| 発行時の案内メール | 送る(宛先 最大 10 件・本文 1000 文字まで)/ 送らない | 送る | 宛先を 1 件も入れなければ送信は起きません。本人確認の宛先が送信先に無いときは警告を出します |
既定値が「安全側」に寄せてある理由
共有リンクは、設定を甘くするほど楽で、厳しくするほど手間がかかります。空欄から始めると、急いでいる人ほど何も設定せずに発行してしまいます。そこで「推奨の設定で開き、緩めたい人だけが緩める」形にしました。パスワードは自動生成なので、良いパスワードを考える負担もかかりません。
トークンとパスワードの保存Token & Secrets
推測できない URL
URL の末尾に付く文字列(トークン)は、32 バイトの暗号学的乱数を base64url で表した 43 文字です。情報量は 256 bit で、総当たりで当てることは現実的にできません。短縮 URL は提供していません(短くすると当てられる余地が生まれるためです)。
トークンはテーブル全体で重複しない制約を持ちます。無効化したリンクの行も残すため、過去に使ったトークンが再び別のリンクに割り当てられることもありません。
パスワードの保存形
パスワードは scrypt というアルゴリズムでハッシュ化して保存します。scrypt は、計算に時間だけでなくメモリも要求するため、専用ハードウェアで大量に総当たりする攻撃に強い方式です。
| 設定 | 値 | 意味 |
|---|---|---|
計算コスト N | 16384 | 1 回の計算にかかる負荷 |
ブロックサイズ r | 8 | 上と合わせて 16 MiB のメモリを要求します |
並列度 p | 1 | — |
| ソルト | 16 バイト | 行ごとに別の乱数。同じパスワードでも保存値が一致しません |
| 導出する鍵 | 64 バイト | — |
保存するのは scrypt$N=16384,r=8,p=1$<ソルト>$<ハッシュ> という1 つの文字列です。ソルト用の列を別に持たず、設定値を値そのものに書き込んでいます。この形にしておくと、将来コストを引き上げても古い行はその行に書かれた設定で検証し続けられるため、全件を作り直す移行作業が要りません。
平文は保存も返却もしません。発行者が確認できるのは発行完了画面の一度きりです。また、ハッシュの計算はデータベースの処理の外で行います。CPU を数十ミリ秒使う処理をデータベースの処理の中に入れると、その間ずっと行を押さえたままになるためです。
案内メールの配送Invitation Email
案内メールは、発行処理の中で直接送っているわけではありません。発行と同じまとまりの中では「送る予定」を記録するだけにして、実際の送信は別の経路が引き受けます。
⑧ 以降は発行者の操作とは切り離して動きます。仮に配送側で障害が起きても、発行そのものは成立しており、送信予定が残っているので復旧後に配送されます。
この段取りにしている理由
もし発行処理の中で直接メールを送ると、送信に失敗したときに発行そのものを取り消すか、取り消さずに「送ったつもり」で進むかのどちらかを選ばされます。前者は「メール障害でリンクが作れない」、後者は「送ったはずのメールが永久に届かない」になります。
そこで、発行と同じまとまりの中では送信予定を 1 行書くだけにしました。この 1 行はリンクの保存と同時に確定するので、「リンクはあるのに送信予定が無い」も「送信予定はあるのにリンクが無い」も起こりません。あとは払い出し役が予定を拾って送るだけです。
共有リンクが送るメールEmails
この仕組みが送るメールは 4 通です。用途によって配送の経路が違います。
| メール | いつ | 誰に | 配送の経路 |
|---|---|---|---|
| 発行時の案内 | 発行時(任意) | 指定した宛先(最大 10 件) | 送信予定 → 払い出し → Pub/Sub → 取込 → 送信 |
| 確認コード | 受取人が本人確認に進んだとき | 発行時に指定した受取人 | Resend へ直送(待たせない・6 桁 / 10 分) |
| 総当たりの検知 | 認証の失敗が短時間に集中したとき | 発行者と管理者 | 送信予定 → 払い出し → Pub/Sub → 取込 → 送信 |
| 強制無効化の通知 | 管理者が強制無効化したとき(任意) | 発行者と Box の Owner | 管理操作から即時送信(件名・本文を管理者が編集) |
確認コードだけ経路が違うのは、受取人が画面の前で待っているからです。ほかの 3 通は数十秒遅れても業務に影響しませんが、確認コードは遅れるとその場で操作が止まります。
案内メールの本文に入るもの・入らないもの
- 入るもの: 受取 URL / 有効期限 / 残りのダウンロード回数 / 発行者の表示名 / 発行時に入力したメッセージ
- 入らないもの: パスワード。代わりに「パスワードは別の連絡手段で発行者からお受け取りください」という固定の案内が入ります(パスワードを設定したときだけ)
- 配信停止のリンクは付きません(社外の受取人はアプリの通知設定を持たないため)
発行時に入力したメッセージは、改行を保ったまま本文に差し込みます。差し込みの際は先にエスケープしてから改行を変換するので、メッセージに HTML を書いても本文には効きません。
発行の完了After Issuing
発行が終わると完了画面が出ます。この画面にはここでしか手に入らないものがあるため、作りにいくつか仕掛けがあります。
| 要素 | 内容 |
|---|---|
| 共有 URL | コピーボタン付き。あとから一覧画面でもコピーできます |
| パスワード | 設定したときだけ表示。この画面を閉じると二度と表示できません(サーバに平文が無いため)。伏せ字と表示切り替え、コピーボタン付き |
| 案内文のコピー | 対象名・URL・「いつまで有効か」・パスワードや本人確認がある旨、をまとめた定型文を 1 クリックでコピー。パスワードそのものは含みません |
| 設定内容 | 期限・回数・本人確認の宛先・案内メールの送信件数を確認できます |
| 閉じ方 | Escape キーや画面外のクリックでは閉じません。「閉じる」を押したときだけ閉じます |
案内文のコピーを用意したのは、「URL だけコピーして、期限や注意書きを毎回自分で書き足す」手間をなくすためです。同時に、その定型文にはパスワードを入れないことで、URL とパスワードを同じメールに貼ってしまう事故を仕組みとして防いでいます。