フロントエンドWeb戦略室

最終回 クライアントサイドでの暗号化とバイナリデータの扱い(1)

この記事を読むのに必要な時間:およそ 4.5 分

最終回となる今回は,Megaというサービスを題材に,クライアントサイドでの暗号化とバイナリデータの扱いについて取り上げます。

Megauploadの閉鎖と復活

2012年1月19日,Megaの前身となるMegauploadが,FBIの強制捜査を受け閉鎖しました注1)⁠Megauploadはオンラインストレージサービスですが,閉鎖時には登録ユーザ数が1億8,000万人,アップロードされたファイルが合計25PB(ペタバイト)あったといいます

Megauploadのようなオンラインストレージサービスを,⁠サイバーロッカー」と呼びます。同種のサービスには,おおむね次のような特徴があります。

  • 大容量のファイルをアップロードすることが可能である
  • 同時ダウンロード数や速度が制限されていて,有料会員登録することでダウンロード速度が速くなる
  • ファイルをアップロードすることで報酬を得られるプログラムがある

実態として,多くの音楽や映画などがアップロードされ,著作権侵害を助長し利益を上げていたとして,コンテンツ産業から問題視されてきました。Megauploadの捜査とサービス閉鎖後,同様のオンラインストレージサービスの多くが,アフィリエイトプログラムの終了や,違法アップロードの自主的な排除の強化など,方針転換を行っています。

知名度が高く,登録ユーザの多いサービスでしたので,⁠著作権を侵害していない」ファイルも数多くアップロードされていました。サービス閉鎖に伴い,Megauploadにアップロードされていたファイルのすべてが参照不可能になり,プライベートなファイル保存目的で使っていたユーザも巻き添えを食らってしまったわけです

1年後の2013年1月19日,Megaとして復活しました。サービスの内容は,⁠ローカルでファイルの内容を暗号化し,運営者からも何がアップロードされているのかわからなくする」というものでした。

注1)
ドメインはFBIによって2013年1月現在も差し押さえられたままです。http://www.megaupload.com/

サービス運営者にも中身がわからない

サービス運営者にも中身がわからない,といったことを売りにするサービスは今までもありました。LastPassのようなパスワード管理サービス,あるいは専用ソフトウェアを使ったストレージサービスのいくつかは「運営者にもわからない暗号化」を行っています。

Megaは,ブラウザだけで大容量ファイルの暗号化/復号を行っているのがポイントです。これだけ大規模なストレージサービスでの暗号化を,ここまで前面に押し出しているのは初めてのことではないかと思われます。Megaを動かすしくみには,つい最近できるようになったフロントエンドの新しい技術が数多く含まれています。JavaScriptに関心のあるエンジニアであれば,興味深いテクノロジがいくつも使われているのです。

Megaに学ぶクライアントサイド技術

というわけでMegaのようなクライアントサイドでの暗号化/復号を行うアップローダのサンプルを作ってみましたので,ソースコード解説をしていきます。サンプルコードは本誌サポートサイトからダウンロードしてください。動作するサンプルは次のURLからアクセスできます注2)⁠

このサンプルには,次の大きな特徴があります。

  • ファイルはブラウザ上で暗号化/復号化を行う
  • 復号にはパスワードが必要だが,パスワードをlocation.hash注3を使って受け渡すことで負担なくダウンロードできる

それではアップロードとダウンロードに分けて,新しいテクノロジの数々を紐解いていきましょう。

注2)
動作環境はInternet Explorer 10,Firefox,Google Chrome,Safari,Operaです。iPhoneからもアクセスができます。
注3
URLの#以降の部分を指します。

暗号化してアップロード

ファイルを暗号化してアップロードするには

  1. ローカルファイルを読み取る
  2. 暗号化する
  3. アップロードする

という3つの処理が必要です。最近のPCとブラウザであれば,数MBのファイルは難なくこなすことができるでしょうが,ここではメモリ消費を抑えるため,すべての処理をストリーミングで行います。

ファイルを受け取る

ブラウザからのファイルアップロードと言えば,伝統的にはinput type = fileを使うことで行えます。

今までは,この方法でJavaScriptから参照可能なファイルの情報は限られていました。ファイル名を取得することはできても,ファイルの中身を読むことまではできなかったのです。

HTML5にてFile APIが整備されたことで,input type = fileによって選択されたファイル,またはドラッグ&ドロップによってブラウザのウィンドウにドロップされたファイルの中身を,JavaScript自身が参照できるようになりました。サンプルではドラッグ&ドロップによってファイルを受け取っています。

分割して読み取る

File APIにより,ブラウザ上のJavaScriptからローカルファイルを参照可能になりましたが,ローカルでこのファイルを暗号化する際,バイナリデータとしてこのファイルを読み取っていく必要があります。ファイル選択ダイアログやドラッグ&ドロップで渡されたファイルは,Fileオブジェクトになっています。Fileオブジェクトには,name(名前)⁠size(ファイルサイズ)⁠type(MIMEタイプ)注4といったプロパティが設定されていますが,ファイルの中身を直接読み取るインタフェースは備わっていません。Fileの中身を読み取るためには次のように,FileReaderを使います。

reader = new FileReader;
reader.onload = function(){
  reader.result;
};
reader.readAsBinaryString(file);

Fileオブジェクトが作られた段階では,Fileの中身は,まだアップロードしているユーザのブラウザのメモリ上に読み込まれていません。この段階では,ディスク上にあるファイルを参照しているだけのオブジェクトです。FileReaderを使うことで,ディスクからファイルの中身を非同期で読み取り,完了次第,onloadイベントが発生します。ただし,こういった普通のやり方でファイルを読み込むと,巨大なファイルを読み込んだ場合には大量のメモリを消費してしまいます。ここでは省メモリで巨大なファイルを取り扱うノウハウが必要です。

単純にFileオブジェクトをFileReaderを使って読み込む場合,巨大なファイルを読み込むとメモリを大量に消費してしまいます。この問題は,Fileオブジェクトを小さく分割しながら,順次読み込んでいくことで回避できます。一度に読み込むファイルのバイト数を設定し,offsetを移動しながらFileオブジェクトの一部分のみを参照するBlobオブジェクト注5を作っていきます。表1に,指定できるクラスの役割を示します。

表1 File APIに関する各クラス

クラス名役割
Blobサイズ固定,不変のバイナリオブジェクト
FileBlobにファイル用のプロパティが備わったもの
FileReaderBlob,Fileを実際に読み込む
注4)
データの形式を直接指定する形式のことです。
注5)
画像や音声などのバイナリデータを格納できるデータ型のことです。

著者プロフィール

mala(マラ)

NHN Japan所属。livedoor Readerの開発で知られる。JavaScriptを使ったUI,非同期処理,Webアプリケーションセキュリティなどに携わる。

Twitter:@bulkneets

コメント

コメントの記入