Piping UIのストリーミングダウンロード時のService Workerへのダウンロード情報への受け渡しをより安全にした変更
Piping UIの0.5.0で反映されたストリーミングしながらのダウンロードをより安全にする変更について。
ストリーミングしながらダウンロードして復号化する
まずPiping UIとはクロスオリジンなPiping Serverからストリーミングしながらダウンロードするために「ファイルのストリーミング強制保存をクロスオリジンでも実現させるService Workerの裏技ぽい使い方」の方法でダウンロードを実現している。大雑把に言えばdocument.createElement('a')で動的に<a>タグを作ってJavaScriptでクリックしたものがService Workerに渡りストリーミングしながらのダウンロードが可能になる。
URLフラグメントへの鍵情報と従来の問題点
Piping UIではE2E暗号化に対応してる。ダウンロード時には復号処理をする必要がある。そのためService Workerが復号に使う鍵を知る必要がある。この鍵は従来のPiping UIでURLフラグメントを使って渡していた。鍵以外にもダウンロードに必要なPiping Serverへのパスや保存後のファイル名などをJSONにしてURLエンコードしてURLフラグメントにしていた。URLフラグメントを使う理由は仮にリクエストがService Workerを突き抜けてWebサーバーに入ったとしてもURLフラグメントはHTTPのリクエストに含まれず鍵情報がWebサーバーのログなどに記録される心配を完全に排除できる。
ただし問題点として、ブラウザのダウンロード履歴などにURLフラグメントは残ってしまう。この問題を修正したのが0.5.0になる。問題といってもパスワードレスで暗号化している場合一度しか使われないエフェメラルな鍵で、ダウンロード履歴ぐらいにしか残らないが、パスワードでの暗号化する時に使い回しをしているような人がいればそれがブラウザのダウンロード履歴に残るはよくないと思っていて変更した。
変更前のダウンロード履歴は以下のようになる。URLエンコードされている分かりhttpsやppng.m..などダウンロードに必要な情報がURLフラグメントに載っていることが分かる。
https://gyazo.com/12acf23c685bac9bf86041404db4f942
変更点
変更後は以下ようなダウンロード履歴になる。
/sw-download#...となっているのが分かる。#以降のURLフラグメントはService Workerが生成したランダムな文字列。このランダムの文字列を生成するにあったって鍵情報は全く使われておらず独立している。
https://gyazo.com/47413c7d680acc6c690e807b69c96607
ダンロードまでの流れに関して。
まず「Service Workerに向かってメッセージを送ってService Worker側から返事を返す方法」使ってService Workerに鍵情報など(ダウンロード情報)が入ったJSONを.postMessage()を使って送り、Service Workerはそのダウンロード情報に対応するように128文字のランダムな文字列を返す。
そして/sw-download#${128文字のランダムな文字列}をダウンロードする。Service Workerではそのランダムな文字列とダウンロード情報の紐付けのハッシュマップがあるため適切なPiping Serverの特定のパスからダウンロードし鍵情報があればそれをつかってストリーミングしながら復号できる。
具体的な変更箇所は: