13 KiB
Netflix Widevine DRM License Exchange - Reference Data
Android アプリ (v9.57.0 / build 63928) から MSL 経由で取得した実データ。 2026-03-13 にキャプチャ。デバイス: Pixel 4a (5G) / Android 14 / Widevine CDM v17.0.0 環境: L3 (ソフトウェア) 強制。レスポンスは Widevine decrypt → CBOR → GZIP → JSON で復元。
概要
Netflix Android アプリは Widevine CDM DRM を使用してコンテンツを保護している。
iOS 版と異なり、マニフェスト取得と初回ライセンス取得が /licensedManifest として統合されている:
- licensedManifest (PRE_FETCH) → ストリーム一覧 + CDN URL + 初回 Widevine ライセンス (limited) を一括取得
- License Request (standard) → 再生開始時に standard ライセンスを取得 (Widevine CDM protobuf チャレンジ)
- License Response → Widevine ライセンスバイナリを受信、コンテンツ鍵を取得
- Release License → 再生終了時にライセンスを解放
ライセンスリクエスト/レスポンスはすべて Widevine CryptoContext で暗号化された MSL ペイロードとして送信される。以下のデータはアプリ内部で MSL 暗号化される前/復号後の平文。
エンドポイント
POST /nq/androidui/samurai/~9.0.0/api
MSL URL としては:
/licensedManifest (マニフェスト + 初回ライセンス一括)
/license?licenseType={standard|limited}&playbackContextId={id}&esn={esn}&drmContextId={id}
URL パラメータ
| パラメータ | 説明 |
|---|---|
licenseType |
standard (再生開始時) or limited (PRE_FETCH / LDL) |
playbackContextId |
licensedManifest レスポンスで取得した再生セッション ID (Base64url-like) |
esn |
Netflix デバイス ESN。NFANDROID1-PRV-P-{L3}-{MODEL}-{userId}-{fingerprint} 形式 |
drmContextId |
DRM コンテキスト ID (数値)。licensedManifest レスポンスの packageId と対応 |
1. licensedManifest Request (PRE_FETCH)
コンテンツ選択時に送信される。iOS の /manifest + /license を統合した Android 固有の API。
バッチリクエストにより複数 viewableId を同時に指定可能。
{
"version": 2,
"url": "/licensedManifest",
"languages": ["en-JP"],
"common": {
"challenge": "<共通 Widevine CDM protobuf>"
},
"params": [
{
"viewableId": "81756595",
"method": "licensedManifest",
"flavor": "PRE_FETCH",
"drmType": "widevine",
"manifestVersion": "v2",
"licenseType": "limited",
"challenges": {
"primary": [{
"challengeBase64": "<Widevine CDM protobuf>",
"drmSessionId": 1,
"clientTime": 1773373148
}]
},
"profiles": ["playready-h264mpl30-dash", "playready-h264hpl22-dash", "..."],
"profileGroups": [{"name": "primary", "profiles": ["..."]}]
}
]
}
iOS との違い
| 項目 | iOS (/manifest + /license) |
Android (/licensedManifest) |
|---|---|---|
| API パス | 分離 (2 リクエスト) | 統合 (1 リクエスト) |
| バッチ | 1 viewableId / リクエスト | 複数 viewableId / リクエスト |
| DRM チャレンジ | FairPlay SPC (個別) | common.challenge + 個別 challenges.primary |
| DRM タイプ | fairplay |
widevine |
| チャレンジ形式 | FairPlay SPC (JSON: CHALLENGES[].PAYLOAD) | Widevine CDM protobuf (バイナリ) |
2. licensedManifest Response
L3 Widevine decrypt → CBOR (key 62) → GZIP 展開で復元。8 チャンク、合計 456KB。
{
"id": 1,
"version": 2,
"serverTime": 1773373149628,
"result": [
{
"movieId": "81756595",
"packageId": "2596051",
"duration": 8523000,
"drmContextId": "2596051",
"playbackContextId": "E3-Bgj5tevc...",
"video_tracks": [{"..."}],
"audio_tracks": [{"..."}],
"timedtexttracks": [{"..."}],
"servers": [{"..."}],
"links": {
"events": {"href": "/events?playbackContextId=...&esn=..."},
"ldl": {"href": "/license?licenseType=limited&..."},
"license": {"href": "/license?licenseType=standard&..."}
}
}
]
}
result フィールド解説
| フィールド | 型 | 説明 |
|---|---|---|
movieId |
string | コンテンツ ID |
packageId |
string | DRM パッケージ ID (drmContextId と対応) |
duration |
number | 再生時間 (ミリ秒)。8523000 = 2時間22分3秒 |
drmContextId |
string | DRM コンテキスト ID |
playbackContextId |
string | 再生セッション ID (後続の /license, /events URL に埋め込み) |
video_tracks |
array | 映像トラック一覧 (複数ビットレート/解像度) |
audio_tracks |
array | 音声トラック一覧 (多言語 × 複数ビットレート) |
timedtexttracks |
array | 字幕トラック一覧 (IMSC 1.1) |
servers |
array | CDN サーバー一覧 (Open Connect Appliance) |
links |
object | 後続 API エンドポイント (events, ldl, license) |
video_tracks の構造
{
"trackType": "PRIMARY",
"new_track_id": "V:2:1;2;;primary;-1;none;-1;",
"dimensionsLabel": "2D",
"streams": [
{
"content_profile": "playready-h264hpl30-dash",
"bitrate": 1050,
"peakBitrate": 2250,
"res_w": 960,
"res_h": 540,
"framerate_value": 24000,
"framerate_scale": 1001,
"size": 1181780966,
"downloadable_id": "1496730611",
"vmaf": 87,
"isDrm": true
}
]
}
L3 環境での最大解像度は 960x540 (SD)。7 ストリーム (80〜1050 kbps)。
servers の構造
{
"id": 140368,
"name": "c062.osa001.ix.nflxvideo.net",
"rank": 1,
"type": "OPEN_CONNECT_APPLIANCE",
"dns": {
"host": "ipv4-c062-osa001-ix.1.oca.nflxvideo.net",
"ipv4": "45.57.82.139",
"ipv6": null
}
}
3 台の Open Connect Appliance (大阪: osa001, osa003)。rank でフェイルオーバー優先度を指定。
iOS manifest レスポンスとの比較
| 項目 | iOS (/manifest) |
Android (/licensedManifest) |
|---|---|---|
| レスポンス取得 | 未取得 | 復元済み (L3 decrypt 経由) |
| result 構造 | 単一オブジェクト (推定) | 配列 (バッチ対応) |
| links | events, license (推定) | events, ldl, license |
| servers | CDN URL 一覧 (推定) | Open Connect Appliance (id, name, rank, dns) |
| video_tracks | 不明 | streams[] (bitrate, res, vmaf, downloadable_id) |
3. Standard License Request
再生開始時に送信される。licensedManifest レスポンスの links.license.href を使用。
{
"version": 2,
"url": "/license?licenseType=standard&playbackContextId=E3-Bgj5tevc...&esn=NFANDROID1-PRV-P-L3-GOOGLPIXEL%3D4A%3D%3D5G%3D-22594-...&drmContextId=2596051",
"params": {
"clientTime": 1773373168,
"challengeBase64": "<Widevine CDM protobuf, ~3.4KB>",
"xid": "7616579701369171345"
},
"languages": ["en-JP"]
}
params フィールド解説
| フィールド | 型 | 説明 |
|---|---|---|
clientTime |
number | クライアント時刻 (Unix epoch, seconds) |
challengeBase64 |
string | Base64 エンコードされた Widevine CDM protobuf ライセンスチャレンジ |
xid |
string | リクエスト ID (トランザクション ID) |
challengeBase64 の内容
iOS の FairPlay SPC が JSON (CHALLENGES[].PAYLOAD) であるのに対し、Widevine は protobuf バイナリ。
内部に以下の情報が含まれる:
| フィールド | 値 | 説明 |
|---|---|---|
esn |
NFANDROID1-PRV-P-L3-GOOGLPIXEL=4A==5G=-22594-... |
デバイス ESN (L3 マーカー含む) |
movieid |
"81756595" |
コンテンツ ID |
issuetime |
1773373148 |
発行時刻 |
salt |
"35982634558192635..." |
ランダムソルト |
oem_crypto_build_information |
"OEMCrypto Level3 Code" |
OEMCrypto セキュリティレベル |
widevine_cdm_version |
"17.0.0" |
CDM バージョン |
device_name |
"bramble" |
デバイスコードネーム |
architecture_name |
"arm64-v8a" |
CPU アーキテクチャ |
4. Standard License Response
{
"id": 1,
"version": 2,
"serverTime": 1773373169221,
"result": {
"licenseResponseBase64": "<Base64-encoded Widevine license protobuf>",
"secureStopExpected": false,
"links": {
"releaseLicense": {
"rel": "releaseLicense",
"href": "/releaseLicense?drmLicenseContextId=E3-Bgj5tevc...;EDEF8BA9-79D6-4ACE-A3C8-27DCD51D21ED;STANDARD;1773373169202"
}
},
"drmGroupId": "132",
"licenseType": "standard",
"expiration": 1773373168000
},
"common": {},
"from": "playapi"
}
result フィールド解説
| フィールド | 型 | 説明 |
|---|---|---|
licenseResponseBase64 |
string | Base64 エンコードされた Widevine ライセンスバイナリ (protobuf)。provideKeyResponse() に渡す |
secureStopExpected |
boolean | Secure Stop (再生終了通知) が必要か |
links.releaseLicense.href |
string | ライセンス解放用 URL。再生終了時にこの URL にリクエストを送る |
drmGroupId |
string | DRM グループ ID。"132" (iOS は "191-192" のようにハイフン区切り) |
licenseType |
string | "standard" |
expiration |
number | ライセンス有効期限 (Unix epoch, milliseconds) |
licenseResponseBase64 の内容
iOS の FairPlay CKC が JSON (VERSION, MEDIASESSIONID, RESPONSES[].PAYLOAD) であるのに対し、
Widevine のライセンスレスポンスは protobuf バイナリ。内部には:
- 暗号化されたコンテンツ鍵: Widevine CDM のセッション鍵で暗号化
- 埋め込み JSON:
version,esn,issuetime,movieid,salt - 鍵 ID:
CE66E4B447F964AC19000000000000000 - ライセンスメタデータ: security_level, expiry_duration
android.media.MediaDrm.provideKeyResponse(sessionId, licenseResponseBase64) に渡すことで
コンテンツ復号鍵が Widevine CDM にインストールされる。
5. Release License (再生終了)
再生終了時、サーバーに通知する。links.releaseLicense.href を使用。
iOS と同じく、レスポンスは空の actions オブジェクト (推定):
{
"result": [
{
"actions": {}
}
],
"id": 1,
"common": {},
"from": "playapi",
"serverTime": 1773373xxx000,
"version": 2
}
6. drmSessionId / videoTrackName フォーマット
V:2:1;2;;primary;-1;none;-1;
セミコロン区切り。推定される構造:
V:2:1— ビデオトラック識別 (V=Video, 以降はインデックス)2— DRM グループ数- (空) — 予約
primary— プロファイルグループ (iOS はce4= HEVC)-1— 品質レベル (-1 = auto)none— HDR タイプ (none = SDR)-1— 予約
7. ESN (Entertainment Service Name) フォーマット
NFANDROID1-PRV-P-L3-GOOGLPIXEL=4A==5G=-22594-3E369F1C9B189ED664E13DEEEE9BACB67684B4FE6283537D1A67810BFE73E371
NFANDROID1— Netflix Android プラットフォーム (iOS はNFAPPL)PRV— プロビジョニングタイプP— 製品タイプL3— Widevine セキュリティレベル (L3=ソフトウェア、L1=TEE)。iOS には存在しないGOOGLPIXEL=4A==5G=— デバイスモデル (Pixel 4a (5G)、=は,のエスケープ)22594— ユーザー ID- 末尾 64 文字 — デバイス固有ハッシュ (SHA-256)
iOS ESN との比較
| 項目 | iOS | Android |
|---|---|---|
| プレフィックス | NFAPPL |
NFANDROID1 |
| DRM バージョン | 02 (FairPlay v2) |
なし |
| セキュリティレベル | なし | L3 or L1 |
| モデル | IPHONE9=1 |
GOOGLPIXEL=4A==5G= |
| ユーザー ID | なし | あり (22594) |
8. データの関連性まとめ
licensedManifest Response
├─ playbackContextId ──→ /license Request URL
├─ drmContextId / packageId ──→ /license Request URL
├─ video_tracks / audio_tracks ──→ CDN ストリーム URL
├─ servers[] ──→ CDN サーバー (Open Connect Appliance)
└─ links
├─ events ──→ /events URL (再生イベント報告)
├─ ldl ──→ /license?licenseType=limited (LDL)
└─ license ──→ /license?licenseType=standard
License Request
└─ challengeBase64 (Widevine protobuf) ──→ License Response.licenseResponseBase64
License Response
├─ licenseResponseBase64 ──→ MediaDrm.provideKeyResponse() → コンテンツ鍵
├─ links.releaseLicense.href ──→ Release License Request URL
└─ expiration ──→ standard: ライセンス有効期限