本章概述#
大多數使用者透過瀏覽器與網站互動。要建立安全的網站,必須理解瀏覽器如何將 HTML 轉換為互動式的視覺頁面。本章涵蓋瀏覽器的 rendering pipeline、browser security model,以及駭客如何嘗試繞過這些安全措施。
Web Page Rendering#
瀏覽器中負責將 HTML 轉換為畫面的軟體元件稱為 rendering pipeline,它負責解析 HTML、理解文件結構與內容,並將其轉換為作業系統可繪製的操作。
- 早期的 HTML 只包含少量樣式資訊(顏色、字型、字體大小),渲染只是依序載入文字和圖片
- 現代 web 開發者將樣式資訊編碼在獨立的 Cascading Style Sheets (CSS) 檔案中
- 像 Google Chrome 這樣的現代瀏覽器包含數百萬行程式碼,用於正確解析 HTML 並處理衝突的樣式規則
The Rendering Pipeline 概覽#
高層流程如下:
- 瀏覽器收到 HTTP response 後,將 HTML 解析為 Document Object Model (DOM) — 一種記憶體中的資料結構,代表瀏覽器對頁面結構的理解
- 對每個 DOM 元素套用樣式規則(styling rules)
- 確定頁面結構後,將網頁繪製到螢幕上
- 以上過程在極短時間內完成,並在使用者互動時重複執行
瀏覽器在建構 DOM 的同時也會載入並執行遇到的 JavaScript,JavaScript 可以動態修改 DOM 和樣式規則。
The Document Object Model (DOM)#
- 瀏覽器收到含 HTML 的 HTTP response 後,將 HTML 解析為 DOM
- DOM 由一系列巢狀的 DOM nodes 組成,每個 node 大致對應原始 HTML 中的一個 tag
- DOM nodes 可以包含文字內容或其他 DOM nodes,形成分支結構,稱為 DOM tree
外部資源載入#
- 某些 HTML tag(如
<script>、<style>、<image>、<font>、<video>)會引用外部 URL - 當這些 tag 被解析進 DOM 時,瀏覽器會發起額外的 HTTP request 來載入外部資源
- 現代瀏覽器會平行執行這些請求以加速頁面載入
容錯機制#
- DOM 的建構設計得盡可能強健
- 瀏覽器會自動關閉未關閉的 tag、插入缺失的 tag、忽略損壞的 tag
- 瀏覽器廠商不會因為網站的錯誤而懲罰使用者
Styling Information#
- DOM tree 建構完成後,瀏覽器需要決定每個元素如何顯示:前景色、背景色、字型、大小、位置、對齊方式等
- 開發者偏好將樣式資訊放在獨立的 CSS 檔案中,與 HTML 內容分離,這樣更容易重新設計樣式,也讓 HTML 保持語義化
- HTML 透過
<style>tag 引用外部 CSS 檔案的 URL
CSS Selectors#
- 每個 stylesheet 包含 selectors,用於選取 HTML 中的特定 tag 並賦予樣式
- Selectors 可以很簡單(例如:所有
<h1>tag 的文字為藍色),也可以很複雜(例如:滑鼠懸停時超連結變色) - Rendering pipeline 需要大量邏輯來決定最終樣式,因為需要遵守嚴格的優先順序規則
業界用來測試瀏覽器對 web 標準遵從程度的基準測試是 Acid3 test,只有少數瀏覽器能拿到滿分 100。

Figure 3-1: Acid3 瀏覽器標準相容性測試
JavaScript#
- JavaScript 是一種完整的程式語言,由瀏覽器的 JavaScript engine 在頁面渲染時執行
- JavaScript 可透過
<script>tag 內嵌於 HTML 中,或更常見地引用外部 JavaScript 檔案 - 預設情況下,瀏覽器一遇到
<script>tag 就立即執行其中的程式碼
defer 屬性#
- 如果 JavaScript 嘗試操作尚未存在於 DOM 中的元素,會導致問題
- 在
<script>tag 加上defer屬性可以讓 JavaScript 延遲到整個 DOM 建構完成後再執行
Browser Security Model 與 Sandbox#
瀏覽器會急切地執行遇到的任何 JavaScript,這帶來嚴重的安全隱患。駭客的目標通常是在其他使用者的機器上遠端執行程式碼。因此,現代瀏覽器透過 browser security model 嚴格限制 JavaScript,要求其在 sandbox 中執行。
JavaScript 不被允許的操作:
- 啟動新程序或存取其他程序
- 讀取任意系統記憶體(JavaScript 是 managed memory language)
- 存取本地磁碟(瀏覽器提供的 local storage 是抽象化的,與檔案系統隔離)
- 存取作業系統的網路層
- 呼叫作業系統函式
JavaScript 被允許的操作:
- 讀取和操作當前頁面的 DOM
- 透過 event listener 監聽和回應使用者動作
- 代替使用者發起 HTTP 請求
- 開啟新頁面或刷新當前頁面的 URL(僅限回應使用者動作時)
- 寫入瀏覽器歷史記錄並進行前進/後退導航
- 請求使用者的地理位置(需使用者授權)
- 請求發送桌面通知的權限
即使有這些限制,注入惡意 JavaScript 仍然非常危險。攻擊者可以透過 cross-site scripting (XSS) 讀取使用者輸入的信用卡資料或登入憑證。即使是極少量的注入程式碼也構成威脅,因為注入的程式碼可以在 DOM 中新增
<script>tag 來載入完整的惡意 payload。XSS 防禦將在 Chapter 7 詳述。
Before and After Rendering: 瀏覽器的其他職責#
瀏覽器不僅僅是 rendering pipeline 和 JavaScript engine,還負責許多其他工作:
- 與作業系統互動以解析和快取 DNS 位址
- 解讀和驗證 security certificates
- 在需要時將請求編碼為 HTTPS
- 根據 web server 的指示儲存和傳送 cookies
實際範例:使用者登入 Amazon#
以下是瀏覽器在使用者造訪 Amazon 時的完整流程:
- 使用者在瀏覽器中輸入
www.amazon.com - 瀏覽器解析 domain 為 IP 位址 — 先查詢 OS 的 DNS cache,再查詢 ISP 的 DNS cache,最後查詢權威 DNS server
- 用解析到的 IP 位址進行 TCP handshake 建立連線
- 建立 TCP session 後,建構 HTTP GET request,TCP 將其拆分為封包送出
- HTTP 對話升級為 HTTPS — 瀏覽器與 server 進行 TLS handshake,協商加密方法並交換金鑰
- Server 透過安全通道回傳包含 Amazon 首頁 HTML 的 HTTP response,瀏覽器解析並顯示頁面,同時觸發大量額外的 HTTP GET request
- 使用者導航到登入頁面,輸入憑證並提交表單,產生一個 POST request
- Server 驗證憑證,透過
Set-Cookieheader 建立 session,瀏覽器儲存 cookie 並在後續請求中自動附帶
本章總結#
- 瀏覽器的 rendering pipeline 將 HTML 解析為 DOM、套用 CSS 樣式規則,最後繪製頁面
- JavaScript 在
<script>tag 中被執行,受到 browser security model 的嚴格限制(sandbox) - 瀏覽器除了渲染頁面外,還負責 DNS 解析、安全憑證驗證、HTTPS 加密、cookie 管理等工作
- 下一章將轉向 HTTP 對話的另一端 — web server