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

时间:2012-03-18 07:53:17

标签: javascript html5 menu html5-video right-click

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

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

23 个答案:

答案 0 :(得分:195)

你不能。那是因为浏览器的设计目的是:提供内容。但是你可以使下载更难

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

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

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

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

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

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

答案 1 :(得分:107)

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

$(document).ready(function(){
   $('#videoElementID').bind('contextmenu',function() { return false; });
});

答案 2 :(得分:34)

简单回答,

你不能

如果他们正在观看您的视频,则已经

  

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

答案 3 :(得分:23)

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

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

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

  2. 将文件保存在名为&#34; .htaccess&#34;的子目录中并添加以下行。

      

    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]
    
  3. 现在源链接无用,但我们仍然需要确保任何试图下载文件的用户都无法直接为该文件提供服务。

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

      <body oncontextmenu="return false;">
      

    2. 结果:

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

        

      错误代码403:FORBIDDEN


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

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

答案 4 :(得分:22)

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

 <body oncontextmenu="return false;">

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

答案 5 :(得分:12)

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

<video id="id" width="320" height="240"  type='video/mp4' controls  > </video>
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();
}

注意:建议不要将此方法用于大文件

修改

  • 使用跨源阻止来避免直接下载

  • 如果视频是通过API传递的,请使用不同的方法(PUT / POST)而不是'GET'

答案 6 :(得分: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>'; 

现在要求PHP发送视频。 PHP恢复文件名;删除会话并立即发送视频。此外,所有“没有缓存”#39;和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:

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

答案 7 :(得分:7)

您可以使用

<video src="..." ... controlsList="nodownload">

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

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

答案 8 :(得分:5)

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

oncontextmenu="return false;"

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

<video oncontextmenu="return false;" controls>...</video>

答案 9 :(得分:4)

我们最终将AWS CloudFront与过期的网址一起使用。视频将加载,但是当用户右键单击并选择另存为时,他们最初收到的视频网址已过期。搜索CloudFront Origin Access Identity。

制作视频网址需要一个可以在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>';

答案 10 :(得分:3)

+1简单和跨浏览器方式: 您还可以使用css z-index和opacity将透明图片放在视频上。 因此,用户将在上下文菜单中看到“将图片另存为”而不是“保存视频”。

答案 11 :(得分:2)

使用Vimeo等服务:登录Vimeo > Goto Video > Settings > Privacy > Mark as Secured,然后选择嵌入域。设置嵌入域后,除非从指定的域连接,否则不允许任何人嵌入视频或从浏览器显示视频。因此,如果您的服务器上有一个安全的页面,它会在iframe中加载Vimeo播放器,那么这就很难绕过它。

答案 12 :(得分:2)

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

网络浏览器会暂时在缓冲区中下载视频,因此如果可以阻止下载,您也可以阻止视频被观看。

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

您应该禁用右键单击,更应该显示消息"You cannot save this video for copyright reasons. Sorry about that."。正如this answer中所述。

这可能非常让用户感到烦恼和困惑。除此之外;如果他们在浏览器上禁用JavaScript,他们能够右键单击并保存。

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

video {
    pointer-events: none;
}

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

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

以下是JSFiddle示例。

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

来自TxRegex answer

<video oncontextmenu="return false;" controls>
    <source type="video/mp4" id="video">
</video>

现在通过JavaScript添加视频:

document.getElementById("video").src = "https://www.w3schools.com/html/mov_bbb.mp4";

功能JSFiddle

防止右键单击的另一种方法是使用embed标记。但是,这并不提供运行视频的控件,因此需要在JavaScript中进行设置:

<embed src="https://www.w3schools.com/html/mov_bbb.mp4"></embed>

答案 13 :(得分:2)

import {BrowserModule} from '@angular/platform-browser';
import {NgModule} from '@angular/core';
import {RouterModule, Routes} from '@angular/router';
import {AppComponent} from './app.component';
import {FetchApiComponent} from './fetch-api/fetch-api.component';
import {FormsModule} from '@angular/forms';
import {HttpClientModule} from '@angular/common/http';
import {UserServiceLatest} from './fetch-latest/app.service';
import {UserServiceTop} from './fetch-top/app.service';
import {YoutubePlayerModule} from 'ngx-youtube-player';
import {SidebarComponent} from './sidebar/sidebar.component';
import {FetchLatestComponent} from './fetch-latest/fetch-latest.component';
import { FetchTopComponent } from './fetch-top/fetch-top.component'
import {UserService} from './fetch-api/app.service';
import { ServiceWorkerModule } from '@angular/service-worker';
import { environment } from '../environments/environment';
import { AngularFireModule } from 'angularfire2';
import * as firebase from 'firebase';
import { firebaseConfig } from './../environments/firebase.config';
import { AngularFireDatabaseModule } from 'angularfire2/database';
import {PushService} from './push.service';

const appRoutes: Routes = [
  {
    path: '',

  component: FetchApiComponent
  }, 
{
    path: '/latest',

    component: FetchLatestComponent
  },
{
    path: '/top',

    component: FetchTopComponent
  },
{
path :'*',
component: FetchApiComponent 
}

];

firebase.initializeApp(firebaseConfig);

@NgModule({
  declarations: [
    AppComponent,
    FetchApiComponent,SidebarComponent, FetchLatestComponent, FetchTopComponent
  ],
  imports: [
    RouterModule.forRoot(appRoutes),
    BrowserModule, YoutubePlayerModule,
    FormsModule,
    AngularFireModule.initializeApp(firebaseConfig),
    AngularFireDatabaseModule,environment.production ?ServiceWorkerModule.register('firebase-messaging-sw.js'):[],ServiceWorkerModule.register('/firebase-messaging-sw.js', { enabled: environment.production }),
    HttpClientModule,environment.production ? ServiceWorkerModule.register('ngsw-worker.js') : [], ServiceWorkerModule.register('/ngsw-worker.js', { enabled: environment.production })
  ],
  providers: [UserService,UserServiceTop,UserServiceLatest,PushService],

  bootstrap: [AppComponent]
})
export class AppModule {}

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

答案 14 :(得分:1)

这是禁用下载的完整解决方案包括右键单击>另存为...在上下文菜单中:

<video oncontextmenu="return false;" controlsList="nodownload">
</video>

答案 15 :(得分:1)

简短回答::像youtube一样对链接进行加密,不知道如何做,不如向youtube / google询问如何做。 (以防万一,您想直截了当。)

我想向任何人指出,这是有可能的,因为youtube做到了,如果他们能做到,那么其他任何网站也可以,而且不是来自浏览器,因为我在Microsoft Edge和Internet Explorer,所以有一种方法可以禁用它,并且看到人们仍然在说...我试图寻找答案,因为如果youtube可以,那么必须有一种方法并且唯一的方法来查看他们的操作方式是有人看着我现在正在做的youtube脚本。我还检查了它是否也是一个自定义的上下文菜单,这不是因为上下文菜单溢出了检查元素,我的意思是就像它在上面一样,我看了一下,并且它从未创建新的类,而且不可能实际上使用javascript访问inspect元素,所以不能。您可以判断何时双击鼠标右键,会弹出chrome上下文菜单。此外... youtube不会在其中添加该功能。我正在做研究,并且正在寻找youtube的来源,所以如果找到答案我会回来的...如果有人说你做不到,那么他们没有像我一样做研究。下载youtube视频的唯一方法是通过视频下载。

好吧...我做了研究,但我的研究仍然是可以禁用它,除非没有JavaScript。...您必须能够加密指向视频的链接才能禁用它,因为我认为,如果找不到它,任何浏览器都不会显示它,当我打开youtube视频链接时,它会显示为“ blob:https://www.youtube.com/e5c4808e-297e-451f-80da-3e838caa1275”(不带引号),因此正在对其进行加密,因此无法保存。 ..您需要了解php,但是就像您从使它变得更难得到的答案中一样,youtube使它成为最难加密的最困难的事情,您需要成为一名高级php程序员,但是如果您不知道那件事,不妨考虑您选择的人是难以下载的最佳答案...但是,如果您知道php比重加密视频链接,那么只能在您的视频上阅读...我不知道如何解释它们做到了,但他们做到了,有办法。 youtube加密视频的方式非常聪明,因此,如果您想知道如何做,而不仅仅是问youtube / google他们是如何做的...希望这对您有所帮助,尽管您已经选择了最佳答案。因此,短期内最好加密链接。

答案 16 :(得分:0)

这就是我的所作所为:

function noRightClick() {
      alert("You cannot save this video for copyright reasons. Sorry about that.");
}
    <body oncontextmenu="noRightClick();">
    <video>
    <source src="http://calumchilds.com/videos/big_buck_bunny.mp4" type="video/mp4">
    </video>
    </body>
这也适用于图像,文本和几乎任何东西。但是,您仍然可以通过键盘快捷方式访问“检查”和“查看源”工具。 (正如顶部的答案所说,你无法完全阻止它。)但是你可以尝试设置障碍来阻止它们。

答案 17 :(得分:0)

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

<video  type="video/mp4" width="330" height="300" controlsList="nodownload" oncontextmenu="return false;" controls></video>

答案 18 :(得分:0)

如果您正在寻找完整的解决方案/插件,我发现这非常有用 https://github.com/mediaelement/mediaelement

答案 19 :(得分:0)

好吧,您无法100%保护它,但可以使其变得更难。我正在解释这些方法,我在研究PluralSightBestDotNetTraining中的保护方法时遇到了它们。但是,这些方法都不能阻止我下载我想要的内容,但是我很难安排下载器通过其保护。

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

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

免责声明

如果有人滥用这些方法或将其用于损害他人或我作为示例提及的网站,我将不承担任何责任。这仅仅是为了共享知识,以帮助您保护自己的知识产品。

生成过期的链接

此操作的要求是为每个用户创建一个下载链接。可以通过天蓝色的blob存储或Amazon s3轻松处理。您可以使用两倍于视频时长过期时间戳的下载链接来创建一个下载链接。那么您需要捕获该视频链接和所需的时间。这是下一种方法所必需的。该方法的不足之处在于,当用户单击播放按钮时,您正在生成下载链接。

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

限制视频请求率

然后监视用户请求第二个视频的速度。如果用户要求下载链接的速度太快,则可以立即将其阻止。您不能将这个阈值设置得太大,因为您可能会错误地阻止仅浏览或浏览视频的用户。

启用HTTP范围

使用诸如videojs之类的js库来播放视频,此外,您还需要在标头中返回一个AcceptRange。 Azure blob存储支持此功能。这样,浏览器便开始逐块下载视频。通常,32字节乘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);
            }
        });
    }

});

无论如何,用户可以使用某种通过流传输下载文件的下载方法来解决此问题。几乎c#可以立即使用,对于nodejs,可以使用request模块。那么您需要启动秒表,收听收到的包裹,并将收到的总字节与总大小进行比较。这样,您可以计算一个百分比以及获得该百分比所花费的时间。然后使用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

检查浏览器代理

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

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

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

检查引荐标头

如果引荐来源网址不是您提供视频的主机URL或页面URL之外的其他内容,则可以禁止该用户,因为他们将下载链接放置在另一个选项卡或另一个应用程序中。甚至您也可以针对进度更新请求执行此操作。

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

要解决此问题,用户可以在下载视频时手动将引荐来源标头设置为等于下载页面的网址。

计算两次请求之间的时间

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

要解决此问题,用户可以在请求之间放置一个随机的睡眠时间。

示例代码

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

答案 20 :(得分:0)

我们可以通过隐藏上下文菜单来简化此操作,

<video oncontextmenu="return false;"  controls>
  <source src="https://yoursite.com/yourvideo.mp4" >
</video>

答案 21 :(得分:0)

看起来像通过websocket流式传输视频是一个可行的选择,就像在流中框架并在画布上绘制它们一样。

Video streaming over websockets using JavaScript

我认为这会提供另一级别的保护,使客户更难以获取视频,当然也可以通过“将视频另存为...”右键单击上下文菜单选项来解决您的问题(矫枉过正?!)。

答案 22 :(得分:-1)

@ Clayton-Graul有我想要的东西,除了我需要使用AngularJS的网站的CoffeeScript版本。万一你需要它,这就是你在AngularJS控制器中放置的内容:

    # This is how to we do JQuery ready() dom stuff
    $ ->
        # let's hide those annoying download video options.
        # of course anyone who knows how can still download
        # the video, but hey... more power to 'em.
        $('#my-video').bind 'contextmenu', -> 
            false

“圈子里正在发生奇怪的事情”(这是真的)