この本を読んだ理由
良い本だという評判は以前から聞いていて、いつか読みたいと思っていました。
技術の基礎になる名著は、できるだけ読んでおきたいと思っています。この本も、その一冊でした。
感想
ブラウザの仕組みに興味がある人なら、読んで損はない一冊だと思います。内容がわかりやすく、最後まで楽しく読めました。
読んでいて新しい発見があっただけでなく、これまで持っていた知識の点と点がつながる感覚もありました。読みやすさも含めて、僕にはかなり合っていた本です。
特に興味深かったのは、サイドチャネル攻撃やXS-Leaks、ブラウザのアーキテクチャにおけるプロセスレベルと論理レベルの隔離についての話。
ブラウザの細かな振る舞いや、わずかな挙動の違いを集めることで、情報を盗み出せる。コンテンツインジェクションによらない、こうした攻撃の考え方は知りませんでした。また、セキュリティの観点からブラウザのアーキテクチャを考えると、プロセスレベルと論理レベルの両方で隔離する設計が必要になることにも納得できました。
普段これだけブラウザを使っているのに、その仕組みをほとんど理解していなかったことに気がついたので、ブラウザやWebセキュリティについて、もう少し深掘りしてみたいです。
読書メモ
この本を振り返りたくなったとき用のメモです。
全体像:Webブラウザは何を守っているのか
この本で特に腑に落ちたのは、Webのセキュリティは単一の仕組みではなく、Origin・Site・Cookie・プロセス・CPUなど異なる境界やレイヤーを組み合わせて成立すること。
- 機密性:権限のない相手に情報を読ませない。
- 完全性:権限のない相手に情報を変更させない。
- 可用性:必要なときにサービスを利用できる。
- SOP/CORS:Originをまたぐ読み取りやDOM操作の制約。
- CSP/Trusted Types/SRI:コードの読み込み・実行や内容の検証。
- Cookie/SameSite:状態の保存・自動送信と、その境界。
- Site Isolation/CORB/CORP:データがレンダラーへ届く範囲やプロセスの隔離。
- XS-Leaks:本文を直接読めなくても、観測できる振る舞いから情報が漏れる問題。
1. SOP・Origin・CORS
Q. SOPはSame-Origin Policy?「別Originへアクセスできない」で合っている?
SOP = Same-Origin Policy。 大枠では合っているが、Cross-Originへのネットワーク通信を一律に禁止するわけではない。特に、別Originのレスポンス本文やDOMをJavaScriptから勝手に読み取ることを制限する。
例えば <img src>、<script src>、フォーム送信、リンクによる遷移などはCross-Originでも可能な場合がある。SOPが送信自体をすべて禁止しないことがCSRFを理解する鍵。
a.example のJS → b.exampleへリクエスト → レスポンス
↓
ブラウザが読み取り可否を判定 Q. OriginとSiteはどう違う?
- Origin = scheme + host + port。パスは含まない。
- SiteはOriginより広い概念。現在のSchemeful Same-Siteでは概ねscheme + 登録可能ドメインで判定する。
https://a.example.com と https://b.example.com
→ Cross-Origin / Same-Site
https://example.com:3000 と https://example.com:4000
→ Cross-Origin(portが異なる)
http://example.com と https://example.com
→ Cross-Origin、Schemeful Same-SiteでもCross-Site Q. CORSは何をする?
CORS = Cross-Origin Resource Sharing。 サーバーがCross-Originでのレスポンス公開を許すか宣言し、ブラウザがその許可を強制する仕組み。
Access-Control-Allow-Origin: https://a.example CORSが許可されないと、通信が発生してレスポンスが返っても、呼び出し元JSに本文が渡らない場合がある。リクエストの種類によってはOPTIONSプリフライトも行われる。
Q. フォーム送信はSOPで禁止されない?
禁止されないケースがある。だから、悪意ある別サイトが被害サイト宛ての操作リクエストを送らせられる。SOPは「勝手に読ませない」側面が強く、勝手に操作させない対策にはCSRFトークンやSameSite等が別途必要。
Q. JSONPとは?
Cross-Originの<script src>が読み込める性質を利用して、サーバーがデータではなくcallback({...})というJSを返す古いデータ取得方式。外部サイトの返すコードをページの権限で実行するため、許可先の信頼が重要になる。現代は通常CORSを使う。
Q. document.domainとは?
関連するサブドメインやポート間のDOMアクセス制限を緩めるための古い仕組み。双方のDocumentが親ドメインを設定する方式だが、現在は非推奨・無効化される環境がある。明示的な情報連携はpostMessageなどで設計する。
2. XSS:どうやって被害者のHTMLにコードが入るのか
Q. XSSは「攻撃者の任意JSをユーザーのブラウザで実行させること」?
ほぼ合っている。より重要なのは、攻撃者のJSを、被害者のブラウザ上で「被害サイトのOriginのコード」として実行させること。
evil.example のJS → bank.exampleの内容を読む → SOPが制限
bank.example に注入された攻撃JS → bank.exampleのOriginで実行 → 同一Originとして動く XSSはSOPをオフにするのではなく、SOPが信頼するOriginの中で攻撃コードを動かす。攻撃コードは被害ページのDOM、JSから読めるストレージ、同一OriginのAPI等にアクセスできる場合がある。
Q. そもそも攻撃者はブラウザのHTMLをどう変更できる?
攻撃者が被害者のブラウザを直接編集するのではない。アプリが外部入力をHTMLやDOMへ安全でない方法で埋め込む箇所を利用する。
- Reflected XSS:URLのクエリ等をサーバーがそのままHTMLに差し込んで返す。
- Stored XSS:攻撃者のコメント等を保存し、他のユーザーにそのままHTMLとして表示する。
- DOM-based XSS:
location.search等の入力をフロントエンドがinnerHTML等に渡す。
const q = new URLSearchParams(location.search).get("q");
result.innerHTML = q; // 外部入力がHTMLとして解釈され得る Reactで通常の<p>{userInput}</p>のようにテキストとして描画する場合はエスケープされるが、dangerouslySetInnerHTML等では注意が必要。
Q. HTML InjectionとXSSは同義?
違う。HTML InjectionはHTMLを混入させること。XSSはJavaScript実行まで達すること。 強いCSPがあるとHTML注入には成功しても、直接のscript実行を防げる場合がある。ただしHTML注入自体も表示偽装などの問題になる。
3. CSP:読み込み・実行のポリシー
Q. CSPの正式名称と意味は?
Content Security Policy(Content Site Policyではない)。そのDocumentでどのリソースを読み込み、どのコードを実行してよいか等を、ブラウザへ宣言する仕組み。
Content-Security-Policy: script-src 'self'; img-src 'self' https://images.example CSPは「JSを提供するサイトのルール」ではなく、基本的にそれを読み込むDocument側のルール。攻撃者のページが被害サイトのJSを読み込む場合、攻撃者のDocumentのCSPがその読み込みを制御する。
Q. CSPがXSSに有効なのはなぜ?
HTML Injectionが起こっても、許可していない外部scriptやインラインscriptの実行をブロックできるため。ただしCSPは不適切なHTML出力の修正に代わるものではない。
-
'unsafe-inline':インラインJSなどを許可し、XSSへの防御を弱め得る。 -
'unsafe-eval':eval()やnew Function()等、文字列をコードとして評価する処理を許可する。 -
base-uri 'none':<base>による相対URLの基準変更を禁止する。 -
'none':指定した種類のリソースの読み込み元を認めない。
Q. nonceとhashベースCSPは?
ドメインを丸ごと信頼するのではなく、許可するscript自体を指定する考え方。
- nonce:レスポンスごとに安全なランダム値を生成し、CSPと許可するscriptタグの値を一致させる。
- hash:インラインscriptの内容のハッシュをCSPに記述し、一致する内容だけ許可する。
Content-Security-Policy: script-src 'nonce-ランダム値' <script nonce="ランダム値">initializeApp();</script> Q. nonce/hashベースは、なぜデプロイが難しい?
- nonce:リクエスト/レスポンス単位で値を作り、CSPヘッダーとHTMLに同期させる必要がある。静的HTML/CDN配信や既存テンプレートの改修が課題。
- hash:scriptの内容変更に伴いhashも変わるため、ビルドとCSP生成の整合性が必要。
- 既存アプリ内のインラインイベントハンドラや
eval()等がブロックされ、既存機能が壊れることがある。
Q. strict-dynamicとは?
nonce/hashで信頼したscriptが、JavaScriptから動的に追加するscriptへ信頼を引き継ぐ仕組み。
Content-Security-Policy: script-src 'nonce-ランダム値' 'strict-dynamic' nonce付きmain.js(信頼の起点)
└ JSから動的に追加したlibrary.js → 許可
└ さらに動的に追加したJS → 許可 HTMLパーサーによって直接挿入されたnonceなしのscriptまで無条件で許可するわけではない。「どこのドメインか」だけでなく「どの信頼済みコードが読み込ませたか」へ発想が移る。
Q. Script Gadgetsは「ライブラリに脆弱性がある」という意味?
近いが、ライブラリの正規機能が、他の条件と組み合わさると攻撃に使える部品になるという方が正確。例えば、攻撃者が注入したHTML属性を信頼済みライブラリが解釈し、式の評価やDOM操作・scriptの動的追加を起こす場合。
HTML Injection
→ 攻撃者がライブラリの処理対象を配置
→ 信頼済みライブラリが読み取る
→ 既存の機能を攻撃に再利用 重要:Script Gadgetは必ずしもstrict-dynamicや外部scriptの動的読み込みを必要としない。信頼済みライブラリの式評価など、それ自体が悪用されるケースもある。
Q. Trusted Typesは?
主にDOM-based XSSを減らす仕組み。innerHTML等の危険なSinkへ生の文字列を渡すことを制限し、安全な変換・検証を通す設計を支援する。
Source=攻撃者が操作し得る入力源。Sink=入力がHTMLやJSとして解釈される危険な箇所。
4. CSPとオープンリダイレクト/情報漏洩
Q. なぜ許可リスト型CSPだけでは不十分?
script-src https://trusted.example は、そのOriginから読み込めるscriptを広く信頼する。許可先にJSONP・オープンリダイレクト・悪用可能なライブラリ等があれば踏み台にされ得る。「信頼できる配信元」と「そこから得られる全コードが安全」は違う。
Q. オープンリダイレクトがCSPのパス制限を回避するとは?
例えば script-src https://a.example https://foo.example/required.js としても、許可先a.exampleの自由なリダイレクトを経由した場合、リダイレクト後のCSP照合で許可リストのパス部分が考慮されないことがある。そのためfoo.example/evil.jsのような、直接なら不許可のパスに到達し得る。ただし、パスが省略されても、リダイレクト先ホストまで無制限に許可されるわけではない。
Q. なぜリダイレクト後はパスを見ないのか?
リダイレクト先パスをCSPのロード成功・失敗に反映すると、その成否を使い、他サイトの秘密のリダイレクト先を推測できる場合があるため。
この説明で混乱したポイントは「攻撃者が被害サイトのCSPを変更できるのか?」だった。攻撃者が設定するのは攻撃者自身のページのCSP。
attacker.example(攻撃者のDocument/CSP)
↓ 被害サイトのURLをリソースとして読み込む
victim.example/redirect
↓ 被害サイト側がユーザー状態に応じて302
victim.example/account または /login
↓
仮にパスによってCSPの成功/失敗が変われば
攻撃者が自分のページで観測して秘密を推測 攻撃サイト自体に同じリダイレクト挙動がある必要はない。リダイレクトするのは被害サイト側。攻撃者のページが開始したリソース読み込みに、攻撃者のDocumentのCSPが適用される。この副作用を防ぐ仕様が、別の場面ではパス制限迂回につながる。
5. Cookie:保存・自動送信・SOPとの境界
Q. Cookieは自動保存される?
原則としてサーバーがSet-Cookieを返すとブラウザが条件を確認して保存し、その後の条件に合うHTTPリクエストへ自動付与する。
Set-Cookie: session_id=abc; Path=/; Secure; HttpOnly レスポンスのSet-Cookie → ブラウザが保存
次回の該当リクエスト → Cookieヘッダーを自動送信 JavaScriptからdocument.cookieでCookieを作ることもできるが、HttpOnly CookieはJSから読めない。
Q. CookieのDomainとは?
どのホスト宛てにCookieを送るかの条件。Domain=example.comならexample.comやサブドメインへ送られ得る。Domain省略時は発行元ホスト専用のhost-only Cookie。
-
Path:送信対象のURLパス。 -
Secure:安全な接続での送信に制限。 -
HttpOnly:JavaScriptによるCookie値の読み取りを制限。 -
SameSite:Cross-Siteでの送信条件。 -
Max-Age:相対的な有効期間(秒)。Expires:絶対的な期限。両方あればMax-Age優先。
HttpOnlyはCookie値を直接盗まれにくくするが、XSSコードによるAPI操作自体は防がない。ブラウザが同一OriginのリクエストへHttpOnly Cookieを自動付与することはある。
Q. Cookieの章にあった3つの問題は?
① CSRF、② プライバシー、③ SOPとCookieのセキュリティ境界のズレ。
① CSRF:Cookieが自動送信される性質を悪用し、ユーザーが意図しない操作リクエストを送らせる。SameSite、CSRFトークン、Origin検証等で対処。
② プライバシー:サイトをまたぐ広告・計測等でCookieが利用され、ユーザーの横断的な追跡が可能になる場合がある。
③ 境界のズレ:SOPはscheme+host+portだが、Cookieはhost/Domain+Path等で判断し、portでは分離できない。
https://example.com:3000 と https://example.com:4000
SOP → 別Origin
Cookie → 同じCookieが双方へ送信され得る
https://example.com/users と https://example.com/admin
SOP → 同じOrigin
Cookie → Pathで送信範囲を分けられる ただしCookie Pathは、互いに信頼できない同一Originアプリを安全に隔離するための強固なセキュリティ境界ではない。
Q. SameSite=Laxと3rd-party Cookieは?
-
Strict:Cross-Siteでは原則送信しない。 -
Lax:Cross-Siteのサブリソース等では制限するが、一般的なトップレベルGET遷移では送信され得る。 -
None; Secure:SameSiteとしてはCross-Site送信を許す。ただしブラウザ自体の3rd-party Cookie制限は別。
3rd-partyはOriginよりSiteの観点で理解する。別サブドメインでもSame-Siteの場合がある。
6. HSTS・HTTPS・SRI
Q. LBでHTTP→HTTPSリダイレクトしていたらHSTSは不要?
役割が異なる。
HTTP→HTTPSリダイレクト
ブラウザ → 最初はHTTP → LBが301 → HTTPS
HSTSを記憶済み
ブラウザ → HTTP URLを内部でHTTPSへ変更 → 最初からHTTPS 最初のHTTPレスポンスはネットワーク上で改ざんされ得る。HSTSはそのホストについてHTTP通信そのものを避ける。80番ポートを閉じても、HSTSを知っていればHTTP URLをHTTPSへ変更できる。
Q. 今のブラウザは初手からHTTPSでは?
現在のブラウザはHTTPSを優先する挙動が進んでいる。ただしHTTPSを試すことと、当該ホストのHTTP通信をポリシーとして禁止することは違う。
Q. HSTS Preloadは何?無料?マスト?
通常HSTSは、初回アクセス時にまだポリシーを知らないTOFU(Trust On First Use)の問題を残す。Preloadはブラウザが最初から対象ドメインのHTTPS必須を知る方式。登録自体は無料だが、登録条件・全サブドメインへの影響・解除反映の遅さなど運用上の制約がある。通常のHSTSとPreloadは別物。個人ブログblog.shimabukuromeg.devについても検討したが、Preloadは必須ではない。申請可否は対象ドメインの条件を別途確認する。
Strict-Transport-Security: max-age=31536000 Q. SRIとは?
Subresource Integrity。CDN等から取得したJS/CSSのハッシュと、HTMLで指定した期待値をブラウザが照合し、内容が違えばブロックする。
<script src="https://cdn.example/library.js"
integrity="sha384-..."
crossorigin="anonymous"></script> - CSP:どんなコード・リソースを読み込み実行してよいか。
- SRI:取得したファイルの中身が期待どおりか。
7. ブラウザの隔離・CPU・サイドチャネル
Q. 論理的隔離とプロセスによる隔離は?
- 論理的隔離:SOPなどのルールで「同じ環境にデータが存在しても読ませない」。
- プロセスレベルの隔離:Site Isolation等で異なるサイトを別レンダラープロセス・アドレス空間へ分ける。
SOP → 同じ部屋でも「見てはいけない」
Site Isolation → そもそも別の部屋にする Q. Site / Site Instance / Browsing Instance・window.openerとは?
- Site:Originより広いサイト単位。
- Browsing Instance:相互に関係を持つウィンドウ・フレームなどのまとまり。
- Site Instance:Browsing Instance内の同一Siteを扱う抽象的な単位。
-
window.opener:開かれたウィンドウが、元のウィンドウへの参照を持つ場合がある。ナビゲーションしても関係が残り得るため、プロセス割り当てに関係する(noopenerやCOOPで切れる場合あり)。
本のProcess-per-Browsing-Instance / Process-per-Site-Instance / Process-per-Siteは、プロセス割り当ての考え方を比較するモデル。
Q. ISA・マイクロアーキテクチャ・投機実行とは?
- ISA:ソフトウェアから見えるCPU命令と動作の約束。
- マイクロアーキテクチャ:パイプライン、キャッシュ、分岐予測、投機実行など内部実装。
- Data Hazard:後続命令が前の命令の結果を待つ依存。
- Stall:その依存等によって処理の進行を待つこと。
- 投機実行:分岐等を予測して先回りする。予測が外れれば正式な計算結果は破棄されるが、キャッシュ等への副作用が残る場合がある。
Q. Spectreではどうやって秘密が漏れる?
投機実行中の秘密に依存したアクセスがキャッシュに痕跡を残し、攻撃者が自分の測定可能なメモリアクセスの速さ・遅さから秘密を推測する。
分岐を誤予測
→ 本来実行しない処理で秘密に依存したアクセス
→ probe[秘密の値]に対応するキャッシュ状態が変化
→ 投機実行の結果は破棄
→ probe候補のアクセス時間を測る
→ 速い候補から値を推測 「秘密のメモリを直接見られる」のではなく副作用を読み解く。ブラウザ経由の攻撃では、悪意あるJSが被害者のブラウザで動き、被害者のCPUが処理する。Site IsolationはCross-Siteの秘密が同じレンダラーアドレス空間へ混在するのを減らす。
Q. CORB・CORP・COEP・COOPの違いは?
- CORB(Cross-Origin Read Blocking):ブラウザ側で一部のCross-Origin HTML/XML/JSON等のレスポンス本文を攻撃側レンダラーへ渡さないようにする。
- CORP(Cross-Origin Resource Policy):リソース提供側が、誰に読み込ませてよいか宣言する(
same-origin、same-site、cross-origin)。 - COEP(Cross-Origin Embedder Policy):読み込むDocument側が、埋め込むリソースに明示的な許可を要求する(例:
require-corp)。 - COOP(Cross-Origin Opener Policy):トップレベルウィンドウ間の関係・分離を制御する。
COEP=読み込む側/CORP=読み込まれる側/COOP=ウィンドウの関係。
X-Content-Type-Options: nosniffは「CORBをONにするスイッチ」ではなく、MIMEの扱いに関する別の保護。
Q. Fetch Metadataと「水際対策」とは?
ブラウザはSec-Fetch-Site、Sec-Fetch-Mode、Sec-Fetch-Dest等でリクエストの文脈をサーバーに伝えられる。サーバーはCross-Siteな不審な取得を判断して、そもそも情報豊富なレスポンスを返さない設計にできる。「返した後、ブラウザで止める」水際対策だけに依存しない発想。
8. XS-Leaks
Q. XS-Leaksとは?「ブラウザの挙動から小さなデータを集めて盗む」で合っている?
XS-Leaks = Cross-Site Leaks。 ほぼ合っている。厳密には、SOPで他サイトのレスポンス本文を直接読めなくても、ロード成否・タイミング・リダイレクトに伴う挙動・キャッシュ・ウィンドウ状態など、外から観測できる差によって、他サイトにあるユーザーの秘密を推測する攻撃群。
本文は読めない
↓
でもログイン済みなら挙動A/未ログインなら挙動B
↓
A・Bの差を観測
↓
ログイン状態などを推測 小さな漏洩を繰り返し組み合わせる場合もあれば、一度の二択で秘密が分かる場合もある。Spectreと「直接読めない情報を副作用から推測する」点は似ているが、XS-LeaksはWebプラットフォームのCross-Siteな挙動、SpectreはCPUの投機実行・マイクロアーキテクチャが主なレイヤー。
メモまとめ:振り返るときの5つの要点
- SOPはCross-Origin通信の全面禁止ではない。 読み取りやDOMアクセスの制限が重要で、CSRFやXS-Leaksはそのすき間を理解すると整理できる。
- XSSの核心は、攻撃者のJSが被害サイトのOriginで動くこと。 入力が安全でないHTML/DOM出力に到達するところが入口。
- CSPは追加の防御壁であり万能ではない。 許可リストの踏み台、nonce/hashの導入コスト、strict-dynamic、Script Gadgetsをセットで理解する。
- セキュリティの境界は統一されていない。 Origin、Site、CookieのDomain/Path、レンダラープロセスはそれぞれ異なる。
- 「直接読めない」≠「秘密が漏れない」。 SpectreやXS-Leaksは、ブラウザやCPUの振る舞いが情報源になり得ることを示す。