阻止下载HTML5视频(右键单击保存)?

pyt*_*hon 156 javascript html5 menu right-click html5-video

如何从浏览器的右键菜单中禁用"将视频另存为..."以防止客户端下载视频?

是否有更完整的解决方案阻止客户端直接访问文件路径?

Jos*_*eph 207

你不能.那是因为浏览器的设计目的是:服务内容.但是你可以下载更难.

首先,您可以禁用该contextmenu事件,即"右键单击".这样可以防止您的常规skiddie通过右键单击并另存为来公然翻录您的视频.但是他们可能只是禁用JS并绕过它或通过浏览器的调试器找到视频源.另外这是糟糕的用户体验.上下文菜单中有许多合法的东西,而不仅仅是另存为.

您还可以使用自定义视频播放器库.他们中的大多数都实现了根据您的喜好自定义上下文菜单的视频播放器.因此,您没有获得默认的浏览器上下文菜单.如果他们确实提供类似于另存为的菜单项,您可以禁用它.但同样,这是一个JS解决方法.弱点与之前的选项类似.

另一种方法是使用HTTP Live Streaming提供视频.它本质上做的是将视频切成块并一个接一个地服务.这是大多数流媒体网站提供视频的方式.因此,即使您设法另存为,也只能保存一个块,而不是整个视频.收集所有块并使用一些专用软件缝合它们需要更多的努力.

另一种技术是<video><canvas>.在这种技术中,通过一些JavaScript,您在页面上看到的是一个<canvas>从隐藏中渲染帧的元素<video>.因为它是一个<canvas>,上下文菜单将使用一个<img>菜单,而不是一个菜单<video>.您将获得"将图像另存为"而不是"将视频另存为".

您也可以使用CSRF令牌.您的服务器会在页面上发送一个令牌.然后,您可以使用该令牌来获取视频.您的服务器在提供视频之前检查它是否是有效令牌,或者获取HTTP 401.我们的想法是,您只能通过拥有一个令牌来获取视频,如果您来自该页面,则只能获得该令牌,而不是直接访问该视频网址.

在一天结束时,我只是将视频上传到第三方视频网站,例如YouTube或Vimeo.他们拥有良好的视频管理工具,优化了设备的播放效果,并且他们努力防止他们的视频因为您的努力而被扯掉.

  • 这取决于浏览器.我已经看过时间(尤其是firefox和chrome),如果视频已满载,当你点击"保存"时,他们只是从缓存中选择视频而不是重新下载(视频已经下载到缓存中,为什么要下载它再次?),因此没有第二个请求.上述方法仅在重用链接时适用. (2认同)
  • 谢谢.我刚看了http://craftymind.com/factory/html5video/CanvasVideo.html.这个想法和你的回答几乎相同. (2认同)

小智 112

对于那些希望简单地从html5视频中删除右键"保存"选项的人来说,这是一个简单的解决方案

$(document).ready(function(){
   $('#videoElementID').bind('contextmenu',function() { return false; });
});
Run Code Online (Sandbox Code Playgroud)

  • 我认为这样做的主要目的是避免"普通"用户下载视频.这是解决这种情况的好方法. (11认同)
  • 但是,如果在浏览器中禁用了JavaScript,则无效. (2认同)
  • 谢谢,这个解决方案足以满足所有访问者的90%. (2认同)
  • 的Bleh.只需检查Firebug中的元素,查看`src`属性,然后在另一个选项卡中打开它或使用`wget`下载它! (2认同)

Sta*_*arx 35

简单回答,

你不能

如果他们正在观看您的视频,他们已经拥有了

你可以放慢速度,但不能阻止它们.

  • 人们可以录制整个屏幕和音频并欺骗所有解决方法,这就是为什么他们只能放慢速度。 (4认同)
  • 每当我搜索使我的用户更难下载或复制我们受版权保护的内容(制作成本昂贵,价格昂贵且是独家内容)的技术时,一些人都会发布“你不能”。显然,从技术上讲,你总是可以想象一种绕过保护措施的方法,但在实践中,如果一个/两个用户破解并分享我们的东西,那并不重要,但如果 100% 这样做,我们公司就完了。 (3认同)
  • 顺便说一句,这个答案适用于 HTML5 视频、Flash 视频或您将来可以想象的任何技术。很简单:这就是它的工作原理。 (2认同)
  • 这不是任何一个问题的答案. (2认同)

Tzs*_*and 27

是的,您可以分三步完成:


  1. 将要保护的文件放在运行代码的目录的子目录中.

    www.foo.com/player.html
    www.foo.com/videos/video.mp4

  2. 将文件保存在名为".htaccess"的子目录中,并添加以下行.

    www.foo.com/videos/.htaccess

    #Contents of .htaccess
    
    RewriteEngine on
    RewriteCond %{HTTP_REFERER} !^http://foo.com/.*$ [NC]
    RewriteCond %{HTTP_REFERER} !^http://www.foo.com/.*$ [NC]
    RewriteRule .(mp4|mp3|avi)$ - [F]
    
    Run Code Online (Sandbox Code Playgroud)

现在源链接是无用的,但我们仍然需要确保任何试图下载文件的用户都无法直接为该文件提供服务.

  1. 对于更完整的解决方案,现在使用Flash播放器(或html画布)提供视频,而不是直接链接到视频.要删除右键菜单,请添加到您的HTML:

    <body oncontextmenu="return false;">
    
    Run Code Online (Sandbox Code Playgroud)


结果:

www.foo.com/player.html 将正确播放视频,但如果您访问www.foo.com/videos/video.mp4:

错误代码403:FORBIDDEN


这将适用于直接下载,cURL,热链接,您可以命名.

这是对所提出的两个问题的完整答案,而不是问题的答案:"我可以阻止用户下载他们已下载的视频吗?"

  • 你仍然可以伪造 HTTP Referer,它允许一个人下载。然而,这是一个非常聪明的解决方案。如果您使用文件上的一次性代码来实现此功能,那么您就可以开始使用了! (3认同)
  • 很好的答案,但你有一个 ` 你应该从你的 `.htaccess` 内容中删除它 (2认同)
  • 看来IDM还是可以下载的! (2认同)

小智 22

我通常使用的最好的方法很简单,我完全禁用整个页面中的上下文菜单,纯html + javascript:

 <body oncontextmenu="return false;">
Run Code Online (Sandbox Code Playgroud)

而已!我之所以这样做,是因为您可以通过右键单击来查看源代码.
好吧,你说:"我可以直接使用浏览器视图源",这是真的,但我们从你不能停止下载html5视频的事实开始.


Saj*_*jan 13

是的你可以:

作为客户端开发人员,我建议使用blob URL,blob URL是引用二进制对象的客户端URL

<video id="id" width="320" height="240"  type='video/mp4' controls  > </video>
Run Code Online (Sandbox Code Playgroud)

在HTML中留下你的视频src空白,并在JS使用AJAX获取视频文件,确保响应类型是blob

window.onload = function() {
    var xhr = new XMLHttpRequest();
    xhr.open('GET', 'mov_bbb.mp4', true);
    xhr.responseType = 'blob'; //important
    xhr.onload = function(e) {
        if (this.status == 200) {
            console.log("loaded");
            var blob = this.response;
            var video = document.getElementById('id');
            video.oncanplaythrough = function() {
                console.log("Can play through video without stopping");
                URL.revokeObjectURL(this.src);
            };
            video.src = URL.createObjectURL(blob);
            video.load();
        }
    };
    xhr.send();
}
Run Code Online (Sandbox Code Playgroud)

  • YouTube现在使用Blob我认为:)? (3认同)
  • 如果我检查页面,在“网络”选项卡中,我会收到一个视频请求,我可以在新选项卡中打开该视频。 (2认同)

B.F*_*.F. 10

PHP将html5视频标记与一个会话一起发送,其中密钥是随机字符串,值是文件名.

ini_set('session.use_cookies',1);
session_start();
$ogv=uniqid(); 
$_SESSION[$ogv]='myVideo.ogv';
$webm=uniqid(); 
$_SESSION[$webm]='myVideo.webm';
echo '<video autoplay="autoplay">'
    .'<source src="video.php?video='.$ogv.' type="video/ogg">'
    .'<source src="video.php?video='.$webm.' type="video/webm">'
    .'</video>'; 
Run Code Online (Sandbox Code Playgroud)

现在要求PHP发送视频.PHP恢复文件名; 删除会话并立即发送视频.此外,必须存在所有"无缓存"和mime类型的标头.

ini_set('session.use_cookies',1);
session_start();
$file='myhiddenvideos/'.$_SESSION[$_GET['video']];
$_SESSION=array();
$params = session_get_cookie_params();
setcookie(session_name(),'', time()-42000,$params["path"],$params["domain"],
                                         $params["secure"], $params["httponly"]);
if(!file_exists($file) or $file==='' or !is_readable($file)){
  header('HTTP/1.1 404 File not found',true);
  exit;
  }
readfile($file);
exit:
Run Code Online (Sandbox Code Playgroud)

现在,如果用户在新标签中复制网址或使用上下文菜单,他将没有运气.

  • 我喜欢这个解决方案——它解决了OP的问题。一件不幸的事情是,当检查 Chrome 中的源代码并右键单击链接时。用户将下载一个 html 文件,该文件实际上是视频文件。 (2认同)

cli*_*ait 10

您可以使用

<video src="..." ... controlsList="nodownload">
Run Code Online (Sandbox Code Playgroud)

https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/controlsList

它不会阻止保存视频,但会删除下载按钮和上下文菜单中的“另存为”选项。


Jcy*_*rss 8

我们可以通过隐藏上下文菜单来使这变得不那么容易,如下所示:

<video oncontextmenu="return false;"  controls>
  <source src="https://yoursite.com/yourvideo.mp4" >
</video>
Run Code Online (Sandbox Code Playgroud)


Mo *_*d A 6

好吧,你不能 100% 保护它,但你可以让它变得更难。我正在解释的这些方法是我在研究PluralSightBestDotNetTraining中的保护方法时遇到的。尽管如此,这些方法都没有阻止我下载我想要的东西,但我很难管理下载器以通过他们的保护。

除了其他提到的禁用上下文菜单的方法之外。用户仍然可以使用第三方工具(例如 InternetDownload 管理器或其他类似软件)来下载视频。我在这里解释的保护方法是减轻那些第三方软件的影响。

所有这些方法的要求是当您发现有人正在下载您的视频时阻止用户。这样,在您禁止他们访问您的网站之前,他们只能下载一两个视频。

免责声明

如果有人滥用这些方法或用它来伤害他人或我所举的网站,我将不承担任何责任。它只是为了分享知识来帮助您保护您的智力产品。

生成有有效期的链接

这样做的要求是为每个用户创建一个下载链接。可以通过 azure blob storage 或 amazon s3 轻松处理这一问题。您可以创建一个具有两倍视频长度到期时间戳的下载链接。那么您需要捕获该视频链接和请求的时间。这对于下一个方法是必要的。此方法的要点是,当用户单击播放按钮时,您将生成下载链接。

在播放按钮事件上,您将向服务器发送请求并获取链接并更新源。

限制视频请求速率

然后您监控用户请求第二个视频的速度。如果用户请求下载链接的速度太快,那么您会立即阻止他们。您不能将此阈值设置得太大,因为您可能会错误地阻止只是浏览或浏览视频的用户。

启用 HTTP 范围

使用一些js库(例如videojs)来播放视频,还需要在标头中返回AcceptRange。Azure Blob 存储开箱即用地支持此功能。这样浏览器就开始逐块下载视频。通常为 32 字节 x 32 字节。那么您需要监听 videojs 的timeupdate变化并更新您的服务器有关视频观看百分比的信息。观看视频的百分比不能超过视频传送的百分比。如果您在交付视频内容时没有收到任何百分比变化,那么您可以阻止该用户。因为他们肯定正在下载。

实现此功能很棘手,因为用户可以向前或向后跳过视频,因此在实现此功能时请注意这一点。

这就是 BestDotnetTraining 处理的方式timeupdate

myPlayer.ready(function () {
    //var player = this;
    this.src({
        type: "video/mp4",
        src: videoURL
    });
    if (videoId) {
        myPlayer.play();
        this.on('timeupdate', function () {
            var currentPercent = parseInt(100 * myPlayer.currentTime() / myPlayer.duration());//calcualte as percentage
            if (currentPercent % 5 == 0) {
                //send percentage to server 
                SaveVideoDurationWatched(currentPercent, videoId);
            }
        });
    }

});
Run Code Online (Sandbox Code Playgroud)

无论如何,用户可以通过使用某种通过流式传输下载文件的下载方法来解决此问题。几乎c#都是开箱即用的,对于nodejs,你可以使用requestmodule。然后您需要启动秒表,监听收到的数据包并将收到的总字节与总大小进行比较。这样您就可以计算百分比以及获得该百分比所花费的时间。然后使用Thread.Sleep()或类似的东西来延迟线程,如果你正常观看视频,你必须等待的时间。此外,在睡眠之前,用户可以调用服务器并更新收到的百分比。所以服务器认为用户实际上正在观看视频。

计算将是这样的,例如,如果您计算出到目前为止您收到了 1%,那么您可以计算出您应该等待休眠下载线程的量。这样,您下载视频的速度就不能超过其实际长度。如果视频时长为 24 分钟。下载需要 24 分钟。(加上我们在第一种方法中设置的阈值)

original video length 24 minute
24 min *60000 = 1,440,000 miliseconds 
1,440,000 % 100 = 14,400 milisecond is needed to download one percent
Run Code Online (Sandbox Code Playgroud)

检查浏览器代理

当您提供网页并提供视频链接或接受进度更新请求时,您可以查看浏览器代理。如果不同则禁止该用户。

请注意,某些旧浏览器不会传递此信息。因此,当视频请求和网页请求中都没有浏览器代理时,您应该忽略这一点。但如果一个请求有,而另一个请求没有,那么您应该禁止该用户。

要解决此问题,用户可以手动设置浏览器代理标头,与他们用来捕获下载链接的无头浏览器相同。

检查引用头

当引荐来源网址不是您的主机 URL 或您提供视频的页面 URL 时,您可以禁止该用户,因为他们将下载链接放在另一个选项卡或另一个应用程序中。即使您可以针对进度更新请求执行此操作。

这样做的要求是拥有视频和显示该视频的页面的映射。您可以创建一些约定或模式来了解 URL 应该是什么,这取决于您的设计。

要解决此问题,用户可以在下载视频时手动将引用标头设置为下载页面 URL。

计算请求之间的时间

如果您收到如此多的请求,以至于它们之间的时间相同,那么您应该阻止该用户。您应该用它来捕获视频链接生成请求之间的时间间隔。如果它们相同(加上/减去某个阈值)并且发生多次,那么您可以禁止该用户。因为如果有一个机器人要抓取您的网站或视频,那么它们通常在请求之间有相同的睡眠时间。因此,如果您收到每个请求,例如,每 1.3(加/分钟一些偏差)分钟。然后你就发出警报。为此,您可以使用一些统计计算来了解请求之间的偏差。

为了解决这个问题,用户可以在请求之间设置随机的睡眠时间。

示例代码

我有一个回购PluralSight-Downloader正在一半完成它。我大约 5 年前创建了这个存储库。因为我编写它是出于学习目的并且仅供个人使用,所以到目前为止该存储库尚未收到任何更新,我不会更新或使其易于使用。这只是一个如何实现的示例。


TxR*_*gex 5

您至少可以阻止非技术人员使用右键单击上下文菜单下载您的视频.您可以使用oncontextmenu属性禁用任何元素的上下文菜单.

oncontextmenu="return false;"
Run Code Online (Sandbox Code Playgroud)

这适用于body元素(整个页面)或仅在视频标记内使用它的单个视频.

<video oncontextmenu="return false;" controls>...</video>
Run Code Online (Sandbox Code Playgroud)


小智 5

我们最终使用了带有到期URL的AWS CloudFront。视频将加载,但是到用户右键单击并选择“另存为”视频URL时,他们最初收到的URL已过期。搜索CloudFront原始访问身份。

产生视频URL需要可以在AWS CLI中创建的密钥对。仅供参考,这不是我的代码,但效果很好!

$resource = 'http://cdn.yourwebsite.com/videos/yourvideourl.mp4';
$timeout = 4;

//This comes from key pair you generated for cloudfront
$keyPairId = "AKAJSDHFKASWERASDF";

$expires = time() + $timeout; //Time out in seconds
$json = '{"Statement":[{"Resource":"'.$resource.'","Condition" {"DateLessThan":{"AWS:EpochTime":'.$expires.'}}}]}';     

//Read Cloudfront Private Key Pair
$fp=fopen("/absolute/path/to/your/cloudfront_privatekey.pem","r"); 
$priv_key=fread($fp,8192); 
fclose($fp); 

//Create the private key
$key = openssl_get_privatekey($priv_key);
if(!$key)
{
    echo "<p>Failed to load private key!</p>";
    return;
}

//Sign the policy with the private key
if(!openssl_sign($json, $signed_policy, $key, OPENSSL_ALGO_SHA1))
{
    echo '<p>Failed to sign policy: '.openssl_error_string().'</p>';
    return;
}

//Create url safe signed policy
$base64_signed_policy = base64_encode($signed_policy);
$signature = str_replace(array('+','=','/'), array('-','_','~'), $base64_signed_policy);

//Construct the URL
$url = $resource.'?Expires='.$expires.'&Signature='.$signature.'&Key-Pair-Id='.$keyPairId;

return '<div class="videowrapper" ><video autoplay controls style="width:100%!important;height:auto!important;"><source src="'.$url.'" type="video/mp4">Your browser does not support the video tag.</video></div>';
Run Code Online (Sandbox Code Playgroud)

  • 如果令牌过期,是否意味着他们也无法浏览视频?因为这似乎又联系到了视频网址。 (2认同)

Sim*_*mon 5

首先要意识到完全防止视频被下载是不可能的,你所能做的就是让它变得更加困难。即你隐藏了视频的来源。

Web 浏览器会临时将视频下载到缓冲区中,因此如果可以阻止下载,您也将阻止视频被查看。

您还应该知道,<1% 的世界总人口将能够理解源代码,因此无论如何都相当安全。这并不意味着您也不应该将它隐藏在源代码中——您应该这样做

你应该不会禁用右键点击,甚至更少,你应该显示一条消息"You cannot save this video for copyright reasons. Sorry about that."。正如这个答案中所建议的那样。

这对用户来说可能是非常烦人和混乱的。除此之外; 如果他们在他们的浏览器中禁用JavaScript的,他们能够点击右键并保存反正。

这是您可以使用的 CSS 技巧:

video {
    pointer-events: none;
}
Run Code Online (Sandbox Code Playgroud)

CSS 不能在浏览器中关闭,保护您的视频而不实际禁用右键单击。然而,一个问题是controls也不能启用,换句话说,它们必须设置为false. 如果您要添加自己的播放/暂停功能或使用具有与video标签分开的按钮的 API,那么这是一个可行的选择。

controls 还有一个下载按钮,所以使用它也不是一个好主意。

这是一个JSFiddle示例。


如果您打算使用 JavaScript 禁用右键单击,那么还要将视频源存储在 JavaScript 中。这样,如果用户禁用 JavaScript(允许右键单击),视频将不会加载(它还可以更好地隐藏视频源)。

TxRegex 回答

<video oncontextmenu="return false;" controls>
    <source type="video/mp4" id="video">
</video>
Run Code Online (Sandbox Code Playgroud)

现在通过 JavaScript 添加视频:

document.getElementById("video").src = "https://www.w3schools.com/html/mov_bbb.mp4";
Run Code Online (Sandbox Code Playgroud)

函数式JSFiddle


另一种防止右键单击的方法是使用embed标签。然而,这不提供运行视频的控件,因此它们需要在 JavaScript 中嵌入:

<embed src="https://www.w3schools.com/html/mov_bbb.mp4"></embed>
Run Code Online (Sandbox Code Playgroud)

  • “CSS 无法在浏览器中关闭” - 从技术上讲,您可以在 Web 浏览器开发人员工具中修改 CSS 以禁用某些 CSS 规则,因此更精通技术的人可以删除 `pointer-events: none;` (2认同)

小智 5

<body oncontextmenu="return false;"> 
Run Code Online (Sandbox Code Playgroud)

不再有效。截至 2018 年 6 月,Chrome 和 Opera 在时间线上有一个允许直接下载的子菜单,因此用户无需右键单击即可下载该视频。有趣的是 Firefox 和 Edge 没有这个......