什麼是 EME?

EME 是簡稱,全名 Encrypted Media Extensions (加密媒體擴充 API),它現在是瀏覽器標準內建的 Web API,讓瀏覽器可以播放受 DRM 保護的影片。使用它的核心目標是讓 HTML5 <video> 支援加密內容,並確保只有合法授權的使用者能夠解碼和播放影片。

要注意的是: EME 不負責解密影片,它只是 API,提供 Interface 與電腦底層 DRM 系統溝通的機制。

為什麼需要 EME?

早年大多數的線上影音網站使用 Flash 或 Silverlight 來播放影片(這些技術也有實作 DRM 的保護機制,例如 Flash 的 Flash Media Rights Management、Silverlight 也能支援 PlayReady)但隨著網路技術的迭代演進,它們逐漸被淘汰,原因如下:

  1. Flash 和 Silverlight 都有安全漏洞,故瀏覽器逐漸停止支援它。
  2. 行動裝置崛起,不支援 Flash
    • iPhone(iOS)從未支援 Flash,這迫使網站改用 HTML5 技術來播放影片。
    • Android 也逐漸放棄 Flash,改用 HTML5 技術來播放影片。

EME 的誕生

雖然 HTML5 的 <video> 標籤取代了 Flash,提供網頁原生影片播放方式,但初期的 HTML5 影片播放並不支援 DRM,影音內容廠商(如 Netflix、Hulu、Disney+)面臨難題,因為他們需要 DRM 來保護內容。

為了讓 HTML5 影片播放 也能支援 DRM,W3C*註 在 2012 年 開始制定 EME 標準,目標是:

  • 讓 HTML5 <video> 具備 DRM 保護功能,取代 Flash/Silverlight。
  • 確保跨平台播放(PC、Mac、手機、智慧電視都能使用相同技術)。
  • 提供內容版權保護,確保 Netflix、YouTube、Amazon Prime Video 等能安全地提供影片。

經過多年的討論與標準化,EME 在 2017 年正式成為 W3C 標準,並被主流瀏覽器(Chrome、Firefox、Edge、Safari)支援。

註:W3C 是負責制定與維護 Web 技術功能和標準規格的國際組織,雖然沒有強制約束力,瀏覽器廠商如 Chrome、Firefox、Safari ..等,還是會盡量參考其制定的規格去實作 Web API 功能。

EME 的陰影

W3C 在 2012、2013 的規格提案還是引發了軒然大波,因為對網路使用者來說,網路應當是自由、開放的,所謂的影片保護機制應是由第三方應用層或影音內容提供者自己去想辦法實作,例如前面提到的 Flash 或 Silverlight,而不是由瀏覽器層原生實作 API 去協助 DRM 商業保護,因為 EME 的實作意味著瀏覽器的功能方向被迫趨於商業現實,服務於資本。

當然除了商業考量外,由瀏覽器方提供相關的 DRM API 確實有些優點在,包含資安、維護性、統一標準等諸多考量,為此 W3C 特別寫了一篇文來解釋,可參考 W3C 中國的翻譯版:https://www.chinaw3c.org/archives/1742/

EME 圍繞的核心:

MediaKeys

代表了一組解密金鑰,讓瀏覽器可以使用適當的 DRM 來解碼受保護的影片。

MediaKeySession

用來處理與 DRM 授權伺服器的互動,負責請求與管理內容的播放授權(license)。

CDM(全名:Content Decryption Module):

每個瀏覽器的內建 DRM 模組(不準確的說法),如:

  1. Widevine(Google Chrome、Android)
  2. PlayReady(Microsoft Edge、Windows)
  3. FairPlay(Apple Safari、iOS/macOS)

這三家前面 DRM 分享者已提過,這裡不多贅述。

整個 EME 就是一系列多個 Web API、methods 圍繞在上述三項,參考 MDN 的 https://developer.mozilla.org/zh-TW/docs/Web/API/Encrypted_Media_Extensions_API

什麼是 CDM?

CDM 全名為 Content Decryption Module(內容解密模組),是 DRM 系統中的核心,負責解密受 DRM 保護的影音內容,並確保內容只能被授權的使用者存取。因為這個功能模組橫跨電腦的瀏覽器層、作業系統層到硬體層,會根據 DRM 系統的安全需求選擇適當的執行方式。

CDM 本身免費,但 DRM 授權需要付費

CDM 本身是免費的,它已經內建在電腦中,但它只是一個「解密模組」,不包含 License 授權,所以我們其實是向 DRM 授權伺服器(License Server) 付費以獲得解密的金鑰。

EME 與 CDM 關係

  • EME 本身不負責解密,而是透過與 CDM 溝通,在瀏覽器或 OS 層執行解密。
  • CDM 是 DRM 系統的核心,負責解密加密內容並確保安全播放。
    • EME 透過 requestMediaKeySystemAccess() 呼叫 CDM,確認支援的 DRM 系統(如 Widevine、PlayReady、FairPlay)。
    • CDM 向並瀏覽器(Browser 層)索取 License 授權。
    • 瀏覽器層將請求傳遞給 Web App(Web 應用層),觸發事件。
    • Web 應用層(Web App)向 License Server 發送請求取得授權。
    • Web 應用層將授權資訊傳回瀏覽器,再透過 EME API 將其傳遞給 CDM。
    • CDM 透過授權解密影片,並將解密後的內容傳遞給媒體播放器,確保內容只能在受信任的環境播放。

簡單來說,EME 是 API,負責與 CDM 溝通,而 CDM 才是真正執行解密的模組。兩者協同運作確保 DRM 內容能夠在 Web 環境播放。

CDM 是如何防止螢幕截圖的?

CDM 橫跨了瀏覽器到硬體層,透過多層級的安全機制來防止螢幕截圖與錄影,主要的防護方式包括:

  1. 硬體級保護(Hardware-Based Protection)
    • 在 Widevine L1、PlayReady SL3000 等高安全等級下,CDM 會依賴 TEE(Trusted Execution Environment) 或 ARM TrustZone 來確保解密後的影片不會進入主記憶體,僅在安全顯示管道中渲染,避免記憶體攔截與畫面擷取。
  2. 作業系統層級防護(OS-Level Protection)
    • Windows 使用 PlayReady 時,可啟用 Windows Protected Media Path(PMP),確保影片僅在受信任的顯示管道中播放,防止螢幕擷取與錄影軟體攔截。
    • macOS/iOS 透過 FairPlay DRM 限制畫面擷取,例如 Safari 播放 Netflix 時截圖顯示黑色或白色畫面。
  3. 瀏覽器與驅動層保護
    • 部分瀏覽器(如 Edge、Chrome)會檢查 是否啟用了「安全輸出路徑」(Secure Output Path),若顯示器不支援 HDCP(High-bandwidth Digital Content Protection),可能降低畫質或拒絕播放。
    • 在 Windows 及 Android,當 CDM 偵測到螢幕錄影軟體執行,可能會直接黑色或白色畫面,或者乾脆顯示錯誤訊息。
CDM 的防護機制仰賴 GPU,所以當你把瀏覽器設定中的「硬體加速」、「GPU 加速」關掉,保護等級直接降低,這時側錄或截圖就會有畫面囉。

Web Client 循序圖

EME 架構中的名詞字典表

目前看到這裡,相信大家對大量名詞有點混亂,所以先放上字典表,讓大家再複習一下名詞與這些角色在其中系統架構的位置。

關鍵字

解釋

CDN、Stream Server

這裡我們就先代指稱:影音內容的儲存與分發系統,負責提供提供加密影片給使用者端(瀏覽器)。

Browser

負責播放影音內容的瀏覽器應用程式,如 Google Chrome、Microsoft Edge、Safari、Firefox..等等。

Media Stack

瀏覽器內部處理影音播放的模組,包括影片解碼、渲染與 EME 互動。

Net

指從 CDN 或授權 Stream Server 拿取影片這件事。

App

這裡指的不是口語上的 Mobile APP,而是指 Web APP「應用程式」,在這份EME 文件、這場分享中是指 Web 網頁或 Web 播放器(如 Video.js、Shaka Player),負責播放影片與呼叫 EME API。

Web Server

處理使用者請求的後端 Server,可轉發 License 請求或 token 等資訊。

License Server

負責管理 DRM 授權,以 token 和 certificate 來驗證使用者權限並發送 License 解密金鑰。

MediaKeys

此份文件前面提過,瀏覽器內部的 DRM 金鑰管理系統,負責解碼受保護影片。

MediaKeySession

此份文件前面提過,適用處理 License 授權請求與 DRM 內容解密的會話機制。

CDM

內建於瀏覽器的 DRM 模組,負責解密受保護的影片。例如:Google Chrome 內建 Widevine CDM,Microsoft Edge 內建 PlayReady CDM。

Platform

包含作業系統與硬體,如 Windows、macOS、iOS、Android,負責支援 DRM 的低階解密與播放技術。

Frame

影片播放時的基本單位,一張一張的影像幀被渲染成流暢的影片。

License

由 License Server 提供的解密金鑰,確保只有授權設備能播放受保護的影片。

舉例:你入住飯店,房間內配有一個保險箱(CDM),內部放有一份機密文件(加密的影片),但你不能直接開啟它,必須向飯店櫃檯(License Server)請求密碼(License),才能解鎖保險箱並取出文件(播放影片)。

隱藏角色

這裡有兩個隱藏角色 token 和 certificate,用來和 License Server 溝通。

以前面的例子來說,我們向飯店櫃檯(License Server)請求密碼,但是櫃檯怎麼知道你就是這間房的房客,總不能大家來拿密碼他都給出去,所以就會有個驗證的機制存在。
不過後面會再介紹,先知道有這兩個角色就好。

關鍵字

解釋

token

確保使用者有觀看權限的憑證,在對 License Server Request 時附加到Header,用來驗證使用者是否有權限觀看、播放區域是否合法等。

certificate

用於確保播放器或裝置是受信任的,並允許與 DRM 授權伺服器進行安全通信。例如 FairPlay 需要 CertBase 憑證,而 Widevine L1 設備內建裝置憑證 來驗證設備的安全性。

實際的循序圖

​網路上關於 DRM 的 B2B 的軟體廠商都有相關的循序圖可參考,這些循序圖均是以 Player 和 Backend、License Server 溝通互動為主,並且對於「Client」端的角色定位則是簡化成「Player 播放器」,所以通常相對單純、好理解。

如果覺得那些循序圖還是不好理解,那接下來可能會有點吃力,因為我們要把前面字典表中的名詞角色加進來了,整個循序圖就會變成下面這樣:

圖片出自於w3c 規格 https://www.w3.org/TR/encrypted-media-2/

可以看到除了 Server 和 Licence Server 以外多了上述提到的東西,而 EME 就是瀏覽器與底層平台系統溝通的橋樑,也就是中間那些箭頭線 methods()

與 License Server 溝通,前端需要帶什麼?

與 License Server 溝通時,前端通常需要帶上 Certificate 和 Token,但 它們的用途不同,而且是否需要帶上是取決於使用哪套 DRM & CDM 系統。

先說結論:Certificate 驗裝置、Token 驗使用者權限

  • Certificate 確保影片只在合法設備上播放,防止未授權存取。
  • 不同 DRM 的 Certificate 運作方式不同:FairPlay 一定要帶,Widevine 視情境不一定。
  • Certificate 影響影片的安全等級,例如 Widevine L1(硬體 DRM)依賴裝置憑證來確保更高的安全性。

Certificate

Certificate(裝置憑證)是 DRM 系統用來確認播放裝置的合法性的數位憑證,確保只有受信任的播放器 / 設備 能與 License Server 進行溝通,並獲得解密金鑰來播放受保護的影片。

在某些 DRM(如 Apple FairPlay、Google Widevine L1)中,Certificate 必須存在,否則 License Server 會拒絕發送 License Key(授權金鑰),影片無法解密。

Certificate 的功能有:

  • 確保播放器或設備受信任
    • 防止未授權的裝置(如未經驗證的瀏覽器、模擬器)獲取解密金鑰。
    • 避免駭客透過逆向工程繞過 DRM 限制。
  • 與 License Server 建立安全連線
    • License Server 透過 Certificate 確保它正在與合法的播放器進行通訊。
  • 限制 DRM 高安全性內容(如 4K / HDR)
    • 一些高級內容(如 Netflix 4K、Disney+ HDR)只有受信任的設備(如支援 Widevine L1 設備)才能播放,這些設備內建裝置憑證,確保影片不能在未授權裝置上解密播放。
  • Certificate 在不同 DRM 系統中的應用:
    • 不同的 DRM & CDM 系統對 Certificate 的要求不一樣。
    • FairPlay(Apple)一定要名為 CertBase 的 Certificate,
    • Widevine 「通常」不需要 Certificate,只要 token 就好。
    • 但是 Widevine 不需要可能會導致無法使用最高等級的 DRM L1 防護。

使用 EME

HTML5 原生使用 EME

const video = document.getElementById("video");
const licenseServerURL = "我們的LicenseServerUrl";
const videoSrc = "我們的加密影片Url"
const keySystem = "com.widevine.alpha"; // CDM 系統的名稱

async function initEME() {
  try {
    // 確認瀏覽器是否支援 Widevine DRM
    const config = [{
      initDataTypes: ["cenc"], // 設定表示這影片用 CENC(Common Encryption)加密
      videoCapabilities: [{ contentType: 'video/mp4; codecs="avc1.42E01E"' }],
    }];

    const access = await navigator.requestMediaKeySystemAccess(keySystem, config);

    // 建立 MediaKeys
    const mediaKeys = await access.createMediaKeys();
    await video.setMediaKeys(mediaKeys);

    // 建立 MediaKeySession 解密會話
    const session = mediaKeys.createSession();

    session.addEventListener("message", async (event) => {
      console.log("建立 session 監聽", event.message);

      // 送出 License Request 到 License Server
      // 這裡是我們前後端溝通重要的一環,因為理論上要加上驗證 Token、視情況加上 Certificate
      const licenseResponse = await fetch(licenseServerURL, {
        method: "POST",
        body: event.message,
        headers: { 
          "Content-Type": "application/octet-stream",
          Authorization: "token",
          "看 License Server 要怎麼定義名稱的 Certificate": "Certificate 憑證"
        }
      });

      const license = await licenseResponse.arrayBuffer();
      console.log("License Received");

      // 傳遞 License 到 MediaKeySession
      await session.update(license);
    });

    // 請求影片的解密金鑰
    const initData = await fetch(videoSrc + ".initData").then(res => res.arrayBuffer());
    await session.generateRequest("cenc", initData);

    // 播放器設定影片並播放
    video.src = videoSrc;
    video.play();
  } catch (error) {
    console.error("EME Initialization Failed:", error);
  }
}

initEME();

Video.js 使用 EME

Video.js 官方已經實作封裝好 EME 的 Web API 套件 videojs-contrib-eme,只需載入和啟動它即可。

import videojs from 'videojs'
import videojs-contrib-eme;

// 建立並初始化播放器
const player = videojs('video-player');

// 當播放器初始化並準備就緒
player.ready(function() {
    
  player.eme(); // 啟用 Video.js 封裝好的 EME 套件

  player.src({
    src: "我們的加密影片Url",
    type: 'application/dash+xml', // 此影音格式,這裡是 DASH 
    
    // keySystem 或 keySystemOptions
    keySystemOptions: [{
      name: "com.widevine.alpha",
      options: {
        serverURL: licenseUri,
        serverCertificate: "Certificate憑證",
        httpRequestHeaders: {
          // 帶上 驗證Token
          // Authorization: "驗證Token"
        },
    }]
  });
  
)}

如果不使用 DRM ,單純用 Video.js 播放 Dash 程式碼範例則如下:

import videojs from 'videojs'

const player = videojs('video-player');

player.ready(function() {

  player.src({
    src: "我們的未加密影片Url",
    type: 'application/dash+xml'
  });
  
})

此篇內容均為網路上可查公開資訊。 另外我也 PR 協助翻譯了此篇:MDN