我是靠谱客的博主 热心网友,这篇文章主要介绍视频服务器常见的防盗链和加密方案大集合,现在分享给大家,希望可以做个参考。

一套「从简到强」的视频分片防盗链 / 加密实战方案,包含可直接落地的 Nginx/OpenResty 配置与生成签名的后端示例(Go)。你可以按需求选 1~2 套组合使用:最常见、够用的是 “时间戳签名 URL +(可选)HLS AES-128 加密(密钥受控发放)”

image.png

一、常见方案对比(结论先行)

方案难度安全性兼容性说明
A. Referer 防盗链只能挡「直链」,易伪造,不建议单独使用
B. 时间戳签名 URL(Nginx secure_link中高最主流、性价比最高;对 HLS/DASH 分片和 m3u8/MPD 都适用
C. 鉴权后 X-Accel-Redirect(内网真实路径 internal先到应用鉴权,通过内网头部放行真实文件;配合短签更稳
D. HLS AES-128 加密 + 受控发放 Key播放器原生支持;密钥 URL 勿裸露,需鉴权或签名
E. 商业 DRM(Widevine/FairPlay/PlayReady)最高需要打包器与 License Server,适合大平台/版权内容
推荐组合:B(签名 URL) + D(HLS AES-128 加密,密钥受控)小而美:B;大而全:B + D;强版权:E。

二、方案 A:Referer 防盗链(入门,不建议单独使用)

# 拦截直链:只允许本站页面引用
location ~* \.(m3u8|ts|mp4|m4s)$ {
    valid_referers none blocked *.yourdomain.com yourdomain.com;
    if ($invalid_referer) { return 403; }
    # 其余正常回源
    root /data/video;  # 或 proxy_pass 后端
}
缺点:Referer 易被伪造、空 Referer(App/隐私模式)会误伤。

三、方案 B:时间戳签名 URL(Nginx secure_link_module

思路:为每个资源(m3u8/ts/m4s)生成带过期时间的签名参数,Nginx 验证后放行。
URL 形如:/vod/xxx.m3u8?e=1735600000&st=Md5OrHmacHash

1) Nginx 配置(MD5 版本,开箱可用)

# http 块开启模块(若编译时已含可忽略)
# load_module modules/ngx_http_secure_link_module.so;

map $arg_e $expires { default $arg_e; }

server {
    listen 80;

    # 保护分片与清单
    location ~* ^/vod/.*\.(m3u8|ts|m4s|mp4)$ {
        # 取 URL 中的 st(签名) 与 e(过期时间)
        secure_link $arg_st,$arg_e;
        # 计算规则:MD5( URI + 过期时间 + secret )
        secure_link_md5 "$uri$arg_e my_super_secret";

        if ($secure_link = "") { return 403; }   # 签名不合法
        if ($secure_link = "0") { return 410; }  # 过期

        # 通过
        root /data/video;  # 或者 proxy_pass 后端
        add_header X-Auth ok always;
    }
}
说明:my_super_secret 替换为你的密钥,保密;$uri 必须与签名计算时的一致(注意大小写和前缀)。

2) 签名生成(Go 示例)

// go get github.com/satori/go.uuid  (如需)
// 计算 st = base64url( md5( uri + e + secret ) )
package main

import (
	"crypto/md5"
	"encoding/base64"
	"fmt"
	"net/url"
	"time"
)

func Sign(uri string, secret string, ttlSeconds int64) (signedURL string) {
	exp := time.Now().Unix() + ttlSeconds
	data := []byte(uri + fmt.Sprint(exp) + secret)
	sum := md5.Sum(data)
	st := base64.URLEncoding.
		WithPadding(base64.NoPadding).
		EncodeToString(sum[:])
	v := url.Values{}
	v.Set("e", fmt.Sprint(exp))
	v.Set("st", st)
	return uri + "?" + v.Encode()
}

func main() {
	uri := "/vod/movie/playlist.m3u8" // 必须与 Nginx 中 $uri 一致
	secret := "my_super_secret"
	u := Sign(uri, secret, 300) // 5 分钟有效
	fmt.Println("Signed URL:", u)
}
用法:你的业务后端(登录态/订单通过后)生成带签名的 m3u8 和分片 URL;播放器直接访问即可(CDN 可缓存命中,不影响验证)。

Tips

  • 也可以把签名只放在 m3u8 上,分片 URL 用相对路径(播放器会继承查询串),简化签名生成。

  • Nginx 新版还有 secure_link_secret + secure_link 组合(HMAC),思路一样,签名更强。

四、方案 C:应用鉴权 + X-Accel-Redirect(“内网真实路径”)

思路:外部 URL 都指向一个应用接口 /auth/vod/xxx.ts;应用层鉴权(用户/订单/IP/频次),通过后返回一个内部头部 X-Accel-Redirect: /internal/vod/xxx.ts,由 Nginx 仅在内网开放真实文件路径(internal)读取文件返回。外部用户永远看不到真实物理路径。

server {
  listen 80;
  root /data/video;

  # 内部真实地址,仅允许 Nginx 自己访问
  location /internal/ {
      internal;
      alias /data/video/;
      # 可再叠加 secure_link(二次保护)
  }

  # 对外暴露的鉴权接口(转发给你的应用)
  location /auth/ {
      proxy_pass http://127.0.0.1:9000;   # 你的 Go/PHP 应用
      proxy_set_header X-Real-IP $remote_addr;
  }
}

应用(示意,Go 伪代码):

// 校验用户/订单/UA/IP/速率...
// 通过后:设置头部让 Nginx 回源内网文件并直接返回给用户
w.Header().Set("X-Accel-Redirect", "/internal/vod/seg-0001.ts")
w.WriteHeader(200)
优点:业务逻辑灵活;缺点:命中应用层,吞吐降低。可与 B 的签名/CDN 缓存结合,提升性能。


五、方案 D:HLS AES-128 加密(关键是密钥受控发放

目标:让分片内容(.ts/.m4s)被 AES-128 加密,播放器解密播放。攻击者即使直链拿到分片也无法解码,除非拿到 密钥 URL。因此要把 密钥 URL 做签名或鉴权

1) 用 FFmpeg 生成加密分片

准备 key_info(三行):

https://yourdomain.com/keys/1001.key?e=1735600000&st=xxxx   # 播放器要去拿密钥的URL(受控)
/opt/keys/1001.key                                            # 服务器本地密钥文件路径(不暴露)
0123456789ABCDEF0123456789ABCDEF                             # (可选) IV,16字节hex


命令:

ffmpeg -i input.mp4 \
  -codec: copy -start_number 0 \
  -hls_time 6 -hls_playlist_type vod \
  -hls_key_info_file key_info \
  -hls_segment_filename "seg-%03d.ts" \
  out.m3u8


out.m3u8 中会包含:

#EXT-X-KEY:METHOD=AES-128,URI="https://yourdomain.com/keys/1001.key?e=...&st=..."


2) Nginx 保护密钥 URL(配合方案 B 的签名)

# 密钥文件真实存储在 /opt/keys,不在静态目录
location /keys/ {
    # 对密钥URL做 secure_link 检验
    secure_link $arg_st,$arg_e;
    secure_link_md5 "$uri$arg_e my_key_secret";
    if ($secure_link = "") { return 403; }
    if ($secure_link = "0") { return 410; }

    alias /opt/keys/;    # 只暴露文件内容(正确设置MIME: application/octet-stream)
    add_header Cache-Control "no-store";
    add_header X-Auth key-ok always;
}


实践要点

  • 不要把密钥文件放在 web 可遍历目录;强制签名或应用鉴权。

  • 密钥轮换:定期生成新 key,新 m3u8 指向新 key;旧内容允许一段时间后失效。

  • 可为 m3u8 与分片 URL 同时加签(B 方案),进一步提升安全。


六、方案 E:DRM(Widevine/FairPlay/PlayReady)

仅在有版权/盗版风险极高时使用。流程是:使用打包器(Shaka Packager、bento4 等)将 CMAF/HLS/DASH 内容做 CENC/SAMPLE-AES 加密;浏览器/App 通过 EME 与 DRM License Server 交互拿到许可证。
特点:最安全、最复杂、成本最高。需要:

  • 打包器(packager)

  • 多 DRM 密钥(KID/KEY)

  • License Server(商用或自建)

  • 播放器需支持 EME(PC/TV/APK)


七、推荐落地组合与部署建议

中小型网站 / 成本敏感

  • B(签名 URL,TTL 1~5 分钟)

  • m3u8 与分片均加签(可只对 m3u8 加签 + 相对路径传播)

  • 前置 CDN,全局缓存(Cache-Control: public, max-age=60),命中过期也会回源验证签名

需要进一步安全

  • B + D(HLS AES-128,Key URL 受控 + 短签有效期)

  • Key 不缓存(no-store),或只对可信 CDN 缓存很短时间

高并发

  • CDN 缓存 + Nginx proxy_cache,签名校验在边缘完成

  • 对 m3u8 设置较短缓存,对分片设置较长缓存,减少源站压力


八、目录结构与示例

/data/
  video/                   # 分片与清单(m3u8/ts/m4s)
  pack/                    # 打包临时目录
/opt/keys/                 # HLS AES-128 密钥(非 web 目录)
nginx.conf                 # 含 secure_link + keys 保护



九、测试方法(验证是否生效)

  1. 签名 URL

# 正确签名
curl -I "https://yourdomain.com/vod/movie/out.m3u8?e=1735600000&st=xxxx"
# 应返回 200,且 X-Auth: ok

# 过期或错误签名
curl -I "https://yourdomain.com/vod/movie/out.m3u8?e=100&st=bad"
# 应返回 410 或 403


  1. 密钥受控

# 不带签名访问 key
curl -I "https://yourdomain.com/keys/1001.key"
# 403

# 带签名访问 key
curl -I "https://yourdomain.com/keys/1001.key?e=1735600000&st=xxxx"
# 200,且 X-Auth: key-ok


最后

以上就是热心网友最近收集整理的关于视频服务器常见的防盗链和加密方案大集合的全部内容,更多相关视频服务器常见内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(354)

评论列表共有 0 条评论

立即
投稿
返回
顶部