結論(Service Workerの利用を把握)
Service Workerの利用を把握するとは、ページとネットワークの間に入ってリクエストを横取りできるService Workerについて、運用者が登録内容を把握しておくことです。どのスクリプトを、どの範囲(スコープ)に、どのキャッシュ・更新方針で登録しているか、侵害時にどう解除するかが対象です。一度登録されるとページを閉じても残るため、XSS修正後も影響が続くおそれがあります。セキュリティAIチェッカーは登録コードがあれば△(要確認)、無ければ対象外とします。
この記事のポイント
- Service Workerはブラウザ内のプロキシとして動き、登録後はページを閉じても残り、スコープ内のリクエストを横取りできます。
- HTTPS(セキュアコンテキスト)でのみ利用でき、スクリプトURLとスコープは同一オリジンに限られます。
- スコープはスクリプトの置き場所が既定の上限で、Service-Worker-Allowedヘッダーが無ければ広げられません。
- スコープを必要なディレクトリに限定し、個人情報やフォーム応答はキャッシュしません。
- 解除用の空のService WorkerやClear-Site-Data: "storage"をキルスイッチとして文書化しておきます。
- 診断はトップページHTMLのserviceWorker.registerの有無だけを見て、あれば△、無ければ対象外です(○は使いません)。
| 診断項目名 | Service Workerの利用を把握 |
|---|---|
| 項目ID | html.service-worker |
| 分類 | HTML・JavaScript・外部資産 |
| 重大度・配点の重み | 低(low) 重み 1 |
| 関連する標準・ガイドライン | OWASP HTML5 Security Cheat Sheet(Web Workers/Service Workersに関する指針)/W3C Service Workers仕様(MDN ServiceWorkerContainer.register())/OWASP WSTG-CLNT-12「Browser Storage」(キャッシュに保存される情報の確認)/CWE-524(機密情報を含むキャッシュの使用)※キャッシュ運用に起因する場合 |
Service Workerの利用を把握するとは
Service Workerは、Webページとネットワークの間に入る「ブラウザ内のプロキシ」として動作するJavaScriptです。一度登録されると、ページを閉じた後もブラウザに残り、登録範囲(スコープ)内のすべてのリクエストを横取りして、キャッシュから応答したり、内容を書き換えたりできます。
// トップページなどに書かれる登録コードの例
navigator.serviceWorker.register('/sw.js');
オフライン表示、プッシュ通知、表示の高速化などに使われ、自治体サイトでも防災アプリ的なPWA(Progressive Web App)化やプッシュ通知で利用されることがあります。
Service Workerの利用を把握するとは、この強力な仕組みについて、次の点を運用者が把握・管理していることを指します。
- どのスクリプトを登録しているか
- どの範囲(スコープ)に登録しているか
- どのようなキャッシュ・更新方針で動かしているか
- 侵害や障害のときにどう解除するか
セキュリティAIチェッカーのこの項目は、トップページのHTMLにService Workerの登録コードがあるかを確認し、ある場合に「スコープとキャッシュ方針を確認すべき」として△(要確認)を出します。登録が無い場合は対象外です。
Service Workerの仕様上の制約(MDN)
MDNの ServiceWorkerContainer.register() の解説によると、Service Workerには次の制約があります。仕様はW3CのService Workersで定められています。
| 制約 | 内容 |
|---|---|
| セキュアコンテキスト限定 | HTTPS(または localhost 等の信頼できるオリジン)でのみ利用できます。MDNは、Service Workerがリクエストとレスポンスを横取り・改変できるため、HTTPでは中間者に悪用されうることを理由に挙げています。 |
| 同一オリジン | 登録するスクリプトURLとスコープは、登録するページと同一オリジンでなければならず、違反すると SecurityError になります。 |
| スコープの既定値と上限 | 既定のスコープはスクリプトが置かれたディレクトリです。スクリプトの場所より広いスコープは、スクリプトの応答に Service-Worker-Allowed ヘッダーで上限を広げない限り指定できません。 |
updateViaCache | 更新確認時にHTTPキャッシュをどう使うか('imports'、'all'、'none')を指定できます。 |
Service Workerのセキュリティ上の論点
OWASPが挙げる指針
OWASPのHTML5 Security Cheat Sheetは、Service Workerについて次の点を挙げています。
- Service Workerを自オリジンからHTTPSで配信すること
- スコープを制限して無関係なパスを横取りしないこと
- 登録解除されるまでキャッシュ応答を返し続けるため、侵害時の「キルスイッチ」を用意すること
- 機密データをキャッシュしないこと(
Cache-Control: no-storeの利用)
特に注意すべき3つの点
- 永続性:XSSなどで攻撃者が自オリジン上に任意のスクリプトを置き、Service Workerとして登録できた場合、XSSを修正した後も登録が残り、以後のページ表示を書き換え続ける可能性があります。自オリジンへのファイルアップロード機能があるサイトでは、アップロードされたJSがService Workerとして登録されないよう、アップロード先のContent-Typeや配信方法を確認します。
- 過大なスコープ:サイトのルート(
/)をスコープとするService Workerは、同じオリジン上で運用している別システム(申請フォーム、職員向け画面など)のリクエストまで横取りします。 - キャッシュの誤り:個人情報を含む応答をキャッシュすると、共用端末で他人に表示されるおそれがあります(CWE-524「機密情報を含むキャッシュの使用」に当たります)。OWASP WSTG-CLNT-12「Browser Storage」でも、キャッシュに保存される情報の確認が求められています。
侵害時の解除手段(Clear-Site-Data)
MDNによると、Clear-Site-Data: "storage" ヘッダーは、localStorage等に加えてService Workerの登録を解除します(セキュアコンテキストのみ)。緊急時の解除手段として把握しておくと有効です。
Service Workerについてよくある誤解
- 「Service Workerを使うこと自体が脆弱性」:適切に管理されたService Workerは問題ではありません。本項目の△は「棚卸しと確認が必要」という意味です。
- 「ファイルを削除すれば止まる」:登録済みのService Workerは、更新確認でスクリプトが取得できなくなっても直ちに消えるとは限りません。新しい空のService Workerで置き換えて
unregister()するか、Clear-Site-Dataを使います。
なお、HTTP応答そのもののキャッシュ制御は「機密ページのキャッシュ制御」と「認証関連ページのno-store」、PWAのもう1つの構成要素であるマニフェストは「Web App Manifestの公開」の各項目で確認します。
Service Workerの利用を把握の診断基準(セキュリティAIチェッカー)
取得対象
- 診断URLへのGETで取得したトップページ(最終URL)のHTML本文(最大2MB)。
- 外部JavaScriptファイルの中身は取得しないため、登録コードが外部JSにある場合は検出できません。
- 登録されたService Workerスクリプト自体(
/sw.js等)の取得や、Service-Worker-Allowedヘッダーの確認は行いません。
判定条件
正規表現 /serviceWorker\.register/i でHTML全体を検索します。
| 判定 | 条件 | 得点への影響 |
|---|---|---|
| ○ 問題なし(pass) | 使用しない(スコープやキャッシュ方針はHTMLから確認できないため) | — |
| △ 要確認(warn) | 登録コード(serviceWorker.register)がある | 1×0.45=0.45点(要確認) |
| × 要改善(fail) | 使用しない | — |
| 対象外(na) | 登録コードが見当たらない | 得点計算から除外 |
この項目は「利用の把握」を目的とした情報収集型の判定です。登録が確認された場合は、根拠欄の「Service Worker登録コードがあります。」をきっかけに、後述のチェックリストで運用状況を確認してください。
得点の読み方
重み1・low項目のため、△になっても総合スコアへの影響は小さく(全適用項目の重み合計が200前後の場合、変動は最大でも0.3点未満)、利用していないサイトとの差は「確認作業が残っている」ことを示すに過ぎません。確認チェックリストを満たしていても自動判定は△のままなので、報告書では「スコープ・キャッシュ方針確認済み」などの運用記録を添えて説明すると、評価の読み違いを防げます。
自治体サイトでの判定例
| トップページの状態 | 判定 |
|---|---|
防災情報のプッシュ通知のため、トップページに navigator.serviceWorker.register('/sw.js') がある | △ |
| PWA対応のCMSテーマが外部JS内で登録している | 対象外(実際には利用しているため、運用側で把握が必要) |
| Service Workerを使っていない | 対象外 |
Service Workerを把握していないとどんなリスクがあるか
攻撃シナリオ(XSSとファイル公開機能が組み合わさった場合)
- 公式サイトのある機能にXSSがあり、同じオリジンに利用者がファイルを置ける仕組み(添付ファイルの公開など)もある。
- 攻撃者はJavaScriptファイルをアップロードし、XSSを使ってそのファイルをService Workerとして登録させる。
- 以後、そのブラウザで公式サイトを開くたびに、Service Workerが応答を書き換えて偽の案内を表示する。XSS自体を修正しても、登録が残る限り影響が続く。
運用上のリスク
- スコープ
/のService Workerが申請システムの応答までキャッシュし、古い画面や他人の入力結果が表示される。 - Service Worker更新時のキャッシュ設定が不適切で、修正版のスクリプトが利用者に長期間届かない。
- 委託事業者が導入したService Workerを職員が把握しておらず、障害時に原因が特定できない。
Service Workerの確認方法と安全な設定(チェックリスト・Apache・nginx・IIS・Next.js)
1. 確認チェックリスト
| 確認項目 | 望ましい状態 |
|---|---|
| 登録スクリプトの場所 | 自オリジン・HTTPSで配信、運用者が管理するパス |
| スコープ | 必要なディレクトリに限定(別システムのパスを含めない) |
Service-Worker-Allowed | 不要なら設定しない |
| キャッシュ対象 | 静的資産(CSS、画像、オフライン用ページ)に限定。個人情報やフォーム応答はキャッシュしない |
| 更新方針 | スクリプトをキャッシュさせない(Cache-Control: no-cache 等)、updateViaCache: 'none' |
| キルスイッチ | 解除手順(空のService Worker、Clear-Site-Data)を文書化 |
2. 登録コードの例(スコープ限定)
防災情報用のService Workerを /bousai/ 配下だけに限定する例です。
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/bousai/sw.js', {
scope: '/bousai/',
updateViaCache: 'none',
});
}
3. スクリプトのキャッシュ制御
修正版のスクリプトが確実に届くよう、Service Workerスクリプト自体をキャッシュさせない設定にします。
Apache(.htaccess)
# Apache (.htaccess)
<Files "sw.js">
<IfModule mod_headers.c>
Header set Cache-Control "no-cache"
</IfModule>
</Files>
nginx
# nginx
location = /bousai/sw.js {
add_header Cache-Control "no-cache" always;
}
IIS(web.config)
<!-- IIS web.config(sw.jsのあるフォルダに配置。locationでsw.jsだけに限定) -->
<configuration>
<location path="sw.js">
<system.webServer>
<staticContent>
<clientCache cacheControlMode="DisableCache" />
</staticContent>
</system.webServer>
</location>
</configuration>
Next.js(Vercel)
Next.js(Vercel)では next.config.js の headers() で source: '/sw.js' に Cache-Control: no-cache を設定します。
4. 緊急時の解除(キルスイッチ)
// 置き換え用の sw.js(自分自身を解除する)
self.addEventListener('install', () => self.skipWaiting());
self.addEventListener('activate', async () => {
await self.registration.unregister();
const clients = await self.clients.matchAll();
clients.forEach((c) => c.navigate(c.url));
});
# 特定ページの応答で登録とストレージを消去(影響範囲が広いので緊急時のみ)
Header always set Clear-Site-Data "\"storage\""
5. 確認方法
- ブラウザの開発者ツール(Application → Service Workers)で、登録スクリプト、スコープ、状態を確認します。
curl -sI https://www.city.example.lg.jp/bousai/sw.jsでContent-Type(JavaScript)、Cache-Control、Service-Worker-Allowedの有無を確認します。
サイトを壊さないための注意点
Clear-Site-Data: "storage"はlocalStorageやIndexedDBも消去します。ログイン状態や入力途中のデータが失われるため、常時設定せず、緊急時に限定したページで使います。- スコープを狭めるとPWAとしてのオフライン表示範囲も狭まります。機能要件と合わせて決めてください。
- 不要になったService Workerは、ファイル削除だけでなく解除用スクリプトを一定期間配信してから撤去します。
よくある質問(FAQ)
Service Workerを使っていると脆弱性があるということですか?
いいえ。適切に管理されたService Workerは問題ではありません。この項目の△は「登録スクリプト・スコープ・キャッシュ方針の棚卸しと確認が必要」という意味です。
sw.jsのファイルを削除すればService Workerは止まりますか?
直ちに消えるとは限りません。登録済みのService Workerは、更新確認でスクリプトが取得できなくなってもすぐには解除されないことがあります。自分自身をunregister()する空のService Workerで置き換えるか、Clear-Site-Dataを使います。
Service Workerのスコープはどう決まりますか?
既定のスコープはスクリプトが置かれたディレクトリです。スクリプトの場所より広いスコープは、スクリプトの応答にService-Worker-Allowedヘッダーで上限を広げない限り指定できません。不要ならこのヘッダーは設定しません。
Clear-Site-Data: "storage"を常に返してもよいですか?
おすすめしません。Service Workerの登録に加えてlocalStorageやIndexedDBも消去するため、ログイン状態や入力途中のデータが失われます。緊急時に限定したページで使います。
対策しても診断結果が○にならないのはなぜですか?
スコープやキャッシュ方針はHTMLから確認できないため、この項目は○を使わず、登録コードがあれば常に△です。重み1のため総合スコアへの影響は小さく、報告書では「スコープ・キャッシュ方針確認済み」などの運用記録を添えて説明してください。
外部JSファイルで登録している場合は検出されますか?
検出されません。診断はトップページHTMLだけを対象にしており、外部JavaScriptファイルの中身や/sw.jsそのもの、Service-Worker-Allowedヘッダーは取得しません。その場合は対象外と表示されますが、実際には利用しているため運用側で把握が必要です。
この項目を含む127項目を、URLを入れるだけで無料診断します。