找出網站中的混合內容 (mixed content)

Google 在 2014 年宣布 HTTPS 將會是搜尋排名的參考之一(相關連結:Official Google Webmaster Central Blog: HTTPS as a ranking signal),到了最近也宣布 Chrome 到了 2017 年 01 月的 Chrome 56 中(相關連結:Google Online Security Blog: Moving towards a more secure web),將會把不是採用 HTTPS 的輸入密碼或信用卡卡號的網站標示為 Not secure(動作超大),最後,會連不是 HTTPS 的網站都標成 Not secure…

blog-image-1
圖片來源:Google Online Security Blog

在把網站從 HTTP 轉到 HTTPS,除了需要調整網頁伺服器上的設定、申請憑證,及把來自 HTTP 的連線都轉到 HTTPS 之外,更費時間的是要確保沒有混合內容 (mixed content) 的情形。

什麼是 mixed content

來看看 Mozilla 的定義:

如果以 HTTPS 傳輸的頁面含有以 HTTP 傳輸的明文內容,則這個連線就只有部分加密:也就是說,未加密的內容就有可能被竊聽或是被中間人修改,連線也就不安全了。當網站發生這樣的情況時,我們說這個頁面含有混和內容

— 取自《混和內容 – Security | MDN》

簡單來說,如果 HTTPS 的網頁中有包含了 HTTP 的連線,就是網頁中有 mixed content。

例如,連線到 https://fmbase.tw/secure-page/,網頁伺服器回應 HTML 給瀏覽器去解析,當有像 <img src=””> 的標籤,需要再發出 HTTP(S) request 來取得圖片,如果當圖片是 HTTP 資源的時候,這個網頁就有 mixed content。

該如何知道有 mixed content

方法 1:瀏覽器

目前的主要的瀏覽器都會提醒使用者 HTTPS 網頁是否有 mixed content:

mixed_content
左圖為正常的 HTTPS 網頁,右圖則是含有非 HTTPS 的資源

也可以利用 Console 或 Network 來找出網頁中哪些是 mixed content:

console_mix_content
Chrome 的 Console tab 中會顯示網頁中哪些資源是不是 HTTPS

方法 2:第三方工具

瀏覽器雖然會告知目前網頁會有哪些是 mixed content,但是要一頁一頁去檢查也是夠累的 (汗),來用一些工具找出網站的哪些頁面說有 mixed content,可以省下很多時間。

以下介紹兩個工具:

方法 3:持續追蹤 mixed content

上面的兩種方式也可以找出網頁中的 mixed content,可是沒辦法一直確保網站的的頁面內容沒有 mixed content,而且如果是需要登入的頁面,方法 2 的工具可能沒辦法找到,所以,第 3 個方式要介紹的概念比較像是,讓使用者協助找出網頁中的 mixed content,當使用者透過瀏覽器連線到網站後,如果含有 mixed content 的話,會回報給設定的伺服器。

HTTP 的基本認識 (如果了解可以忽略)

連線到網站時,瀏覽器除了取得到網頁伺服器回應的像 HTML 等資源外,還包含 HTTP headers ,HTTP headers 是網頁伺服器 (server) 與客戶端 (client) 溝通的方式,所以能在伺服器端設定 HTTP response 中的 headers 要包含什麼資訊。

進入正題

來追蹤 HTTPS 網頁中的 mixed content,主要是利用 Content Security Policy (CSP) 中的 Content-Security-Policy-Report-Only HTTP header,在說明如何來實作追蹤 mixed content 前,先簡單介紹 Content Security Policy (以下就簡稱 CSP)。

使用 CSP 會在網頁伺服器回應給瀏覽器中的 HTTP headers 加入了 Content-Security-Policy 的欄位,讓瀏覽器知道哪種資源可以允許的來源有哪些,以下舉個定義 CSP 的例子:

瀏覽器存取的所有資源只能是同源 (Same origin),也就是與網頁相同 domain 且同樣的連線協定:

  • Content-Security-Policy:HTTP header 的欄位,後面接的是規則
  • default-src:控制資源 (resource),default 則是如果當其他資源都沒被定義,則採用 default,default-src 包含了這些
  • ‘self’:來源 (source),指與目前連線頁面的 domain,協定及 port number 相同,注意必須要有單引號

有時候,有些網站會把 CSS 或 JavaScript 資源放在 CDN 或是 Amazon S3 上,這樣可能會沒辦法是相同的 domain,可以把上面的規定改成:

上面的 CSP 規則加入了:

  • script-src:JavaScript 的資源
  • code.jquery.com maxcdn.bootstrapcdn.com:允許的來源域名,空白隔開

另外,如果遇到圖片可能用到了 data URI (如: Data URIs | CSS-Tricks):

加入了以下規則:

  • img-src:圖片資源
  • data::允許透過 data URI 取得圖片,後面必須有冒號

看到這裡,應該會發現 CSP 是白名單 (whitelist) 機制,也就是 CSP 規範的資源 (resource) 允許透過哪些來源 (source),如果沒有允許的話,就是違反了 CSP(除非 default-src 允許),當違反了 CSP 且瀏覽器有支援 CSP 的話,就可能看不到正確的內容。

這裡可以取得到更多 CSP 更多定義資源 (resource)來源 (source) 的資訊。

簡單瞭解 CSP 可以對哪些資源制定規則之後,來說明如何透過 CSP 的功能得知網站中哪些頁面是有 mixed content。

實作追蹤 mixed content

在上面介紹 CSP 的時候有提到,如果瀏覽器發現違反了 CSP 的話,使用者沒辦法正確瀏覽內容,所以 CSP 裡還加入了回報的機制,回報主要有兩個部分:

  • Enforced:在 Content-Security-Policy 中加入 report-uri,瀏覽器會強制不執行違反 CSP 的資源,並將違反 CSP 的情況紀錄給指定的伺服器
  • Report only:在 Content-Security-Policy-Report-Only 中加入 report-uri,瀏覽器還是會去執行違反 CSP,也會把違反紀錄回報給指定的伺服器

這兩個差別只在於,瀏覽器會不會強制不執行違反 CSP 的規則,在還沒確定設定的 Content-Security-Policy 之前,可以先用 Content-Security-Policy-Report-Only,來抓出設定或網站需要調整的地方。

設定 CSP 必須為 HTTPS 來源,找出 mixed content:

當網頁中有包含不是 HTTPS 的連線,瀏覽器會發出 HTTP POST request 到 https://example.report-uri.io/r/default/csp/reportOnly endpoint,伺服器會儲存、搜集瀏覽器的回報的資料。

HTTP response 的 header 在網頁伺服器上加入設定,下面以 Nginx 為例:

看到這裡應該會發現,還需要負責搜集 CSP 回報的資料服務,如果不想自己建立 CSP report 搜集的服務,可以考慮使用 report-uri.io 提供的免費服務。

設定沒問題的話,在瀏覽到 mixed content 網站應該可以從瀏覽器的 Console 中看到以下結果:

report-only

使用了 report-uri.io,能在 report-uri.io 的後台看到哪些網頁的資源違反了定義的 CSP:

report-only-io

參考資料:

找出網站中的混合內容 (mixed content)

發表迴響

你的電子郵件位址並不會被公開。 必要欄位標記為 *