HTML video 标签无法真正防下载,仅靠 oncontextmenu="return false" 等前端拦截脆弱无效;真正有效的是 MediaSource API 分片加载+服务端鉴权与响应头严格控制。

video 标签默认不阻止右键,禁用靠的是事件拦截而非 HTML 结构
HTML 本身没有属性能真正“防止下载”,<video> 的 controls、preload 或 poster 都不影响右键菜单出现。所谓“防下载”实际依赖 JavaScript 拦截 contextmenu 事件,或移除视频源的直接可访问路径。纯 HTML 结构无法实现防护,但可以为后续 JS 控制打基础。
关键点:
-
<video>必须省略src属性,改用<source>动态注入,否则用户仍可在元素面板里看到完整 URL - 避免在 HTML 中硬编码 MP4/HLS 地址,尤其不能放在
src或data-src这类易被爬取的属性里 - 使用
poster属性时,图片地址也需注意——它同样可被直接访问,不应存放敏感资源
如何用 oncontextmenu="return false" 拦截右键(简单但脆弱)
这是最常见的一行写法,加在 <video> 标签上:
<video controls oncontextmenu="return false"> <source id="video-source" type="video/mp4"> </video>
但它只阻止浏览器默认右键菜单,用户仍可通过以下方式获取视频:
立即学习“前端免费学习笔记(深入)”;
- 打开开发者工具 → Elements → 找到
<source>的src值 → 粘贴到新标签页下载 - Network 面板过滤
media或mp4,找到真实请求 URL - 禁用 JS 后,该属性完全失效
所以它仅适合对普通用户做轻量干扰,不能视为安全措施。
真正有效的做法:用 MediaSource API + fetch 分片加载
绕过直接暴露视频 URL 的唯一可靠方式,是不用 <source src="xxx.mp4">,而是通过 MediaSource 把二进制流喂给 <video>。这样 Network 面板看到的是多个小片段请求,且无完整文件链接。
基本流程:
- 创建
MediaSource实例,挂载到<video>的src - 用
fetch请求分段视频(如每 2MB 一个 blob),再用appendBuffer()写入SourceBuffer - 服务端需支持字节范围请求(
Rangeheader),并校验 Referer / Token - 全程不出现可直链的 .mp4 地址,URL 可带一次性签名参数(如
/video/chunk?id=abc&token=xyz)
示例关键代码片段:
const mediaSource = new MediaSource();
video.src = URL.createObjectURL(mediaSource);
mediaSource.addEventListener('sourceopen', () => {
const sourceBuffer = mediaSource.addSourceBuffer('video/mp4; codecs="avc1.42E01E"');
fetch('/api/video/chunk?sig=abc123')
.then(r => r.arrayBuffer())
.then(buf => sourceBuffer.appendBuffer(buf));
});容易被忽略的泄露点:CORS、Referer、缓存头
即使用了 MediaSource,如果服务端配置不当,视频依然可能被截获:
- 响应头缺少
Access-Control-Allow-Origin: *或未精确匹配前端域名 → 导致 JS 无法 fetch,但反而让调试者更早意识到后端存在 → 更容易逆向分析接口 - 没限制
Referer→ 攻击者伪造 Referer 即可批量请求分片 - 返回头含
Cache-Control: public→ 视频片段可能被 CDN 或浏览器缓存,之后从缓存中提取 - 错误信息暴露路径,比如 403 返回体里写
{"error": "invalid token for /videos/1001.mp4"}→ 直接给出原始文件名
真正的防护不在前端结构,而在服务端鉴权粒度、响应头控制、以及是否允许跨域资源读取——这些比 HTML 怎么写重要得多。



















