Service Worker とは
Service Worker は、Web ページとは別のプロセスとして、バックグラウンドで実行されるスクリプトです。
典型的な用途としては、以下のようなものがあります。
- キャッシュ管理
- ネットワークリクエストをキャッシュし、オフラインでもサイトを表示できるようにする
- プッシュ通知
- サーバーからのプッシュ通知を受け取り、ユーザーに表示する
- バックグラウンド同期
- オフライン時のユーザー操作をキューに入れ、オンライン復帰時にサーバーと同期する
これらに加え、Service Worker の強力な機能の一つに 「ブラウザがリクエストを送信し、レスポンスを受け取るまでの間に処理を挟める(プロキシとして振る舞える)」 という点があります。
fetch イベントをフックすることで、ネットワークリクエストを横取りし、レスポンスを自由に加工してブラウザ(ページ)に返すことができます。
Instant Lock
この仕組みを利用し、「サーバー上には暗号化されたファイルを置いておき、ブラウザが読み込む直前に Service Worker で復号する」ツールとして instant-lock を開発しました。
静的なサイトホスティングサービスで、簡易的なパスワード保護(暗号化)を実現するために使うイメージです。
- GitHub
- npm
以下のコマンドでディレクトリを丸ごと暗号化できるようにしています。
npx @instant-lock/cli encrypt -i ./docs -o ./encrypted -p mysecretpassword -t "My Private Docs"
注意: これはあくまで「難読化」に近いものであり、セキュリティを保証するものではありません。
技術的な解説
instant-lock では、ビルド時にすべてのリソースを AES で暗号化し、閲覧時に Service Worker 上で復号して表示します。
暗号化から表示までのシーケンス
-
暗号化 (ビルド時):
- 静的サイトのファイルを、パスワードから生成した鍵(PBKDF2)とランダムな IV を用いて AES-GCM で暗号化します
- 暗号化されたファイルには、復号に必要な Salt と IV、そしてマジックバイトが付与されます
-
初回アクセス:
- ユーザーがサイトにアクセスすると、まず暗号化されていないブートストラップ用の
index.htmlが読み込まれます - ここにはパスワード入力フォームと、Service Worker の登録スクリプトが含まれています
- ユーザーがサイトにアクセスすると、まず暗号化されていないブートストラップ用の
-
復号と表示 (Service Worker):
- ユーザーがパスワードを入力すると、Service Worker が有効化され、パスワードがメモリ上に保持されます
- 以降、ブラウザからのリクエスト(画像やCSS、HTMLなど)はすべて Service Worker が横取りします
-
index.htmlへのリクエストは__index.htmlの中身を返却するようになります - Service Worker はサーバーから暗号化されたデータを取得し、保持しているパスワードを使ってオンメモリで復号します
- 復号されたデータは適切な
Content-Typeと共にブラウザへ返されます
これにより、ブラウザ(DOM や JavaScript エンジン)からは通常のファイルとして見えますが、ネットワーク上を流れるデータやサーバー上のファイルは暗号化された状態となります。
実際の動作
実際に GitHub Pages 上で動作しているデモを用意しました。
-
https://hnisiji.github.io/
- パスワード:
password123
- パスワード:
実際にホスティングされているリポジトリを見ると、ファイルが暗号化されていることがわかります。
hnisiji/hnisiji.github.io
-
index.htmlやsw.js以外は開いても意味不明な文字列になっています- リポジトリ上の
index.htmlはブートストラップ用のコードに置き換わっており、元のコンテンツは__index.htmlに暗号化されて保存されています
- リポジトリ上の
最後に
開発や記事の執筆は、Gemini Code Assist にかなりの部分をやってもらっています。すごい...