使用m3u8进行视频播放时,防盗链的方法主要有两种:一种是基于HTTP Referer的防盗链,另一种是基于token的防盗链。

  1. HTTP Referer防盗链:服务器在返回m3u8文件或ts文件时,检查HTTP请求头中的Referer字段,只有来自指定域名的请求才会被接受。这种方法的优点是实现简单,缺点是Referer字段可以被修改,安全性不高,而且一些播放器可能不一定支持refer设置。
  2. Token防盗链:服务器在返回m3u8文件时,在URL中添加一个token参数,这个token是根据某种算法(如HMAC)生成的,只有知道这个算法的人才能生成或验证这个token。当用户请求ts文件时,服务器会检查token是否有效,只有有效的token才能访问ts文件。这种方法的优点是安全性高,缺点是实现较复杂。

步骤

  1. 例如从地址:https://xxxx.net/drm/hls/process/vod/339131249426778112/d3363c1dfe295328e18a53e194c298c7/v.f100000.m3u8 下载的下列文件如下,其中ts不是全路径,EXT-X-KEY也是无法直接拿来解析,这样即使抓包获取链接也无法定位ts资源,无法下载或者播放。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:10
#EXT-X-MEDIA-SEQUENCE:0
#EXT-X-KEY:METHOD=AES-128,URI="MDc5MTdkNzNjOTFiMzYwMDQzMzBjOTQ4MjFmZDIwN2EtNWZiOTUwOTY0NjZkMTEyYTQ5MWI1ZTVlOGQxMzkyMzQ4ZDJhYWJhYw==",IV=0x00000000000000000000000000000000
#EXTINF:10.000000,
v.f100000_0.ts
#EXTINF:10.000000,
v.f100000_1.ts
#EXTINF:10.000000,
v.f100000_2.ts
#EXTINF:10.000000,
v.f100000_3.ts
#EXTINF:10.000000,
v.f100000_4.ts
#EXTINF:10.000000,
v.f100000_5.ts
#EXTINF:10.000000,
v.f100000_6.ts
#EXTINF:10.000000,
v.f100000_7.ts
#EXTINF:10.000000,
v.f100000_8.ts
#EXTINF:10.000000,
v.f100000_9.ts
#EXTINF:10.000000,
v.f100000_10.ts
#EXTINF:10.000000,
v.f100000_11.ts
#EXTINF:10.000000,
v.f100000_12.ts
#EXTINF:10.000000,
v.f100000_13.ts
#EXTINF:10.000000,
v.f100000_14.ts
#EXTINF:10.000000,
v.f100000_15.ts
#EXTINF:10.000000,
v.f100000_16.ts
#EXTINF:10.000000,
v.f100000_17.ts
#EXTINF:10.000000,
v.f100000_18.ts
#EXTINF:10.000000,
v.f100000_19.ts
#EXTINF:3.960000,
v.f100000_20.ts
#EXT-X-ENDLIST
  1. 客户端下载到该文件之后,第一步根据EXT-X-KEY的加密方法和key内容,该内容不是为ts解密所用,而是通过解密之后的内容作为服务端接口的参数,从而获取真正的解密key,写入到本地目录,更新m3u8文件的EXT-X-KEY字段的uri为http://127.0.0.1/xxx.key。
  2. 替换原文件的没行ts地址,拼接上全路径https://xxxx.net/drm/hls/process/vod/339131249426778112/d3363c1dfe295328e18a53e194c298c7/
  3. 利用App的本地轻量server环境(GCDWebserver), 在客户端播放器播放http://127.0.0.1/xxx.m3u8。做好请求路由返回正确的FileResponse即可。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
let localServer = GCDWebServer()
localServer.addDefaultHandler(forMethod: "GET", request: GCDWebServerRequest.self) { request in
let path = request.path

guard let m3u8Path = M3U8ParseManager.getM3U8DirectoryPath()
else { return GCDWebServerResponse(statusCode: 404)}
if path.hasPrefix("/m3u8/") {
let fileName = path.replacingOccurrences(of: "/m3u8/", with: "")
let filePath = "\(m3u8Path)/\(fileName)"
let fileResponse = GCDWebServerFileResponse(file: filePath)
fileResponse?.contentType = "application/octet-stream"
return fileResponse
}
if path.hasPrefix("/key/") {
let fileName = path.replacingOccurrences(of: "/key/", with: "")
let filePath = "\(m3u8Path)/\(fileName)"
let fileResponse = GCDWebServerFileResponse(file: filePath)
fileResponse?.contentType = "application/octet-stream"
return fileResponse
}
return GCDWebServerResponse(statusCode: 404)
}