229

How can I disable "Save Video As..." from a browser's right-click menu to prevent clients from downloading a video?

Are there more complete solutions that prevent the client from accessing a file path directly?

Braiam
  • 1
  • 11
  • 47
  • 78
python
  • 2,677
  • 3
  • 17
  • 15
  • 4
    I up-voted this question because it only *absolutely asks* for how to "disable the right-click" for an HTML5 video. I am not sure if it is similar to right-click disabling for normal images or if there are other overlay tricks, etc., that can be applied. –  Mar 18 '12 at 08:35
  • 12
    Even if you disable right-click, they can still save it from the browser menu (`File→Save As`). Even if you could somehow block that, they can *view-source* to find the URL of the file. Even if you could obscure that a bit, they can rip it from the cache. Even if you could complicate that (e.g., stream), they can capture the network traffic with a sniffer or something. The fact is, if you send it to a user, they can save it. No way around that. The question you need to ask is why you need to stop it so badly. Is it really even that necessary? Is it worth the effort and user-unfriendly–ness? – Synetech Jul 25 '15 at 00:43
  • I'm going to look pedantic here, but you're overloading the term "download". You of course *do want* to allow the video to be downloaded. – Johan Boulé Jul 13 '18 at 14:11

28 Answers28

320

You can't.

That's because that's what browsers were designed to do: Serve content. But you can make it harder to download.


Convenient "Solution"

I'd just upload my video to a third-party video site, like YouTube or Vimeo. They have good video management tools, optimizes playback to the device, and they make efforts in preventing their videos from being ripped with zero effort on your end.


Workaround 1, Disabling "The Right Click"

You could disable the contextmenu event, aka "the right click". That would prevent your regular skiddie from blatantly ripping your video by right clicking and Save As. But then they could just disable JS and get around this or find the video source via the browser's debugger. Plus this is bad UX. There are lots of legitimate things in a context menu than just Save As.


Workaround 2, Video Player Libraries

Use custom video player libraries. Most of them implement video players that customize the context menu to your liking. So you don't get the default browser context menu. And if ever they do serve a menu item similar to Save As, you can disable it. But again, this is a JS workaround. Weaknesses are similar to Workaround 1.


Workaround 3, HTTP Live Streaming

Another way to do it is to serve the video using HTTP Live Streaming. What it essentially does is chop up the video into chunks and serve it one after the other. This is how most streaming sites serve video. So even if you manage to Save As, you only save a chunk, not the whole video. It would take a bit more effort to gather all the chunks and stitch them using some dedicated software.


Workaround 4, Painting on Canvas

Another technique is to paint <video> on <canvas>. In this technique, with a bit of JavaScript, what you see on the page is a <canvas> element rendering frames from a hidden <video>. And because it's a <canvas>, the context menu will use an <img>'s menu, not a <video>'s. You'll get a Save Image As instead of a Save Video As.


Workaround 5, CSRF Tokens

You could also use CSRF tokens to your advantage. You'd have your sever send down a token on the page. You then use that token to fetch your video. Your server checks to see if it's a valid token before it serves the video, or get an HTTP 401. The idea is that you can only ever get a video by having a token which you can only ever get if you came from the page, not directly visiting the video url.


ioannis-kokkalis
  • 432
  • 1
  • 3
  • 13
Joseph
  • 117,725
  • 30
  • 181
  • 234
  • 1
    thank you for the detail answer, is it possible at least disable the save as option from the right click menu? it will cover most basic knowledge cases – python Mar 18 '12 at 08:43
  • 3
    that depends on the browser. i have seen times (especially firefox and chrome) that if the video is fully loaded, when you hit "save" they just pick the video from the cache instead of re-downloading (the video is already downloaded in the cache, why download it again?), thus there is no second request. the method above is applicable only when the link is reused. – Joseph Mar 18 '12 at 08:49
  • actually i would less mind if they download it from the cache or the server, i understand that this cannot be prevented for 100%, but i would like at least when clients right click on the video the Save As option will apear in gray or will not be visible, i believe it will prevent from the 80% avrage users from downloading the content – python Mar 18 '12 at 09:14
  • 1
    well, i found an article talking about overlaying the video tag with a div. updated my answer – Joseph Mar 18 '12 at 09:25
  • 3
    Thanks. I Just read http://craftymind.com/factory/html5video/CanvasVideo.html. The idea is almost same as your answer. – Trung Jun 19 '13 at 04:26
  • Hi Joseph, shouldn't the `src` parameter be a video resource location only, like `foo.mp4`? Otherwise, if it's a backend script mentioned in the 'src', how do I *stream the video and destroy the token from the server*? – SexyBeast Sep 03 '14 at 11:30
  • 1
    @Cupidvogel The "onetime use url" is a server endpoint which accepts a server generated token. The token is generated upon page generation, and saved to the db. It is also shipped with the page as `src` of the ` – Joseph Sep 04 '14 at 02:27
  • What do you mean by *don't stream the file*? – SexyBeast Sep 04 '14 at 16:25
  • @Cupidvogel Don't serve the file. The endpoint `media.php` in the answer) serves as a "gate" to access the file. Either have a valid token or don't get the file. – Joseph Sep 04 '14 at 19:38
  • Yes, how does the `php` file serve as a *gate*, serving the file? I am kind of new to `php`. :( – SexyBeast Sep 04 '14 at 23:30
  • 1
    after the server validate the token and start stream the video, it will stream using a URL anyway (http://cdn.example.com/video.mp4), so if I can capture this URL, your video can be streamed by anyone. Can prevent this from happening? – Xianlin Sep 25 '14 at 08:11
  • There is a permissions-based and *simple* solution below, used by enterprises. – Tzshand Dec 26 '16 at 16:46
  • 1
    How would this work for pseudo-streaming (using range requests)? If the url is only valid once, if you skip to the end of the video and back to the beginning, the player won't be able to grab the data from the server. – fiffy Jun 23 '17 at 07:16
  • I'm sorry, but, overlay video under other element, cant work, mobile browser cannot use autoplay, so its impossibe to play, maybe you can use other button to play. And will still can use CTRL U to the sources from code, so easy as right button. I think most effetive solluction is use the CANVAS,users could save a image, and canvas works a painting canvas. we can draw it, draw it again, then draw it again, i havent done that, but as developer i think i need try it. when you use Flash, there was a plugin, that used to mark the sources. youtube dont use canvas and no token (as porn sites) . – David Augustus Nov 30 '17 at 21:20
  • The browser doesn't do a GET of the src URL until the user hits play. So, to get around the token-based method would be easy. Load the page, get the special URL from the source, and wget that URL. It's used once, but by wget, not the browser. – Greg Bell Dec 21 '17 at 12:02
  • Does the canvas technique still work for anyone else? I'm able to save the video from the example page given, so I'm wondering if perhaps this used to work and doesn't anymore – Grace Aug 03 '18 at 07:12
  • Can you share a resource on how to use HLS to serve the video file? – Whip Mar 28 '20 at 10:42
132

This is a simple solution for those wishing to simply remove the right-click "save" option from the html5 videos

$(document).ready(function(){
   $('#videoElementID').bind('contextmenu',function() { return false; });
});
Clayton Graul
  • 1,445
  • 1
  • 10
  • 7
59

Yes, you can do this in three steps:


  1. Place the files you want to protect in a subdirectory of the directory where your code is running.

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

  2. Save a file in that subdirectory named ".htaccess" and add the lines below.

    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]
    

Now the source link is useless, but we still need to make sure any user attempting to download the file cannot be directly served the file.

  1. For a more complete solution, now serve the video with a flash player (or html canvas) and never link to the video directly. To just remove the right click menu, add to your HTML:

    <body oncontextmenu="return false;">
    


The Result:

www.foo.com/player.html will correctly play video, but if you visit www.foo.com/videos/video.mp4:

Error Code 403: FORBIDDEN


This will work for direct download, cURL, hotlinking, you name it.

This is a complete answer to the two questions asked and not an answer to the question: "can I stop a user from downloading a video they have already downloaded."

Timo Schwarzer
  • 399
  • 4
  • 17
Tzshand
  • 1,575
  • 11
  • 14
49

Simple answer,

YOU CAN'T

If they are watching your video, they have it already

You can slow them down but can't stop them.

Community
  • 1
  • 1
Starx
  • 77,474
  • 47
  • 185
  • 261
  • 2
    By the way, this answer apply with HTML5 videos, flash videos, or any technology you can imagine in the future. It's simple: it's how it works. – Gustavo Rodrigues Aug 24 '15 at 22:06
  • And what about youtube?, on youtube you cannot discove the video file easily. I mean that ok, you are right, we can, but is easily to hide the mp4 source on youtube or similar video hosting than host a simple mp4 in our server and use the html5 player. – dlopezgonzalez Nov 17 '16 at 16:33
  • 3
    That is not an answer to either of the questions. – Tzshand Dec 29 '16 at 03:14
  • However, the segmented streaming video way is practically efficient way for almost 99% of hackers who wanna downloading your video). – Scott Chu May 02 '18 at 04:10
  • @ScottChu, Well, maybe but still you can't prevent it. – Starx May 02 '18 at 08:30
  • 6
    People could record their entire screen and audio and fool all workarounds, that is why they can only be slowed down. – kintsukuroi Apr 28 '20 at 06:11
  • 2
    Everytime I searched about techniques to make it harder for my users to download or copy our copyrighted contents (which is expensive to make, sold at expensive price and is exclusive content) some people post "you can't". Obviously technically you could always imagine a way to hack around protections but in practice if one/two users hack and share our stuff it doesn't matter but if 100% do it our company is over. – Ilan Schemoul Jul 03 '20 at 12:06
  • @IlanSchemoul I agree with your view. At most, a complex protection will only act as a deterrent for the less ambitious ones. And, for people who can't do it themselves will find their way to a place where the people who do know, will make it available to them. So at the end you just slowed them down. Business can evolve by accepting this fact and focus on creating a business model around it now. e.g. You can restrict unlicensed commercial use, and as soon as an illegal use is big enough, sue them for the damage otherwise its free promotion. – Starx Jul 06 '20 at 13:29
  • @Starx we make worksheets for an exam in france which is passed by only ~7000 people. Members sharing our content won't do it on the web publicly but will share it to their friends if they can easily. Either it Is easy (click right copy/paste) and every single student will do it (because we have very high quality, expensive, 100% exclusive content) and our business is over. Or it is complex (HTTP live stream) and no one or maybe 1/2 will search advanced way around our copyrighted content because they won't share it publicly (we know most internet groups about the exam we help students pass) – Ilan Schemoul Jul 06 '20 at 14:43
  • 1
    @IlanSchemoul Interesting. Thanks for sharing :) – Starx Jul 06 '20 at 18:15
28

The best way that I usually use is very simple, I fully disable context menu in the whole page, pure html+javascript:

 <body oncontextmenu="return false;">

That's it! I do that because you can always see the source by right click.
Ok, you say: "I can use directly the browser view source" and it's true but we start from the fact that you CAN'T stop downloading html5 videos.

Christian Giupponi
  • 7,408
  • 11
  • 68
  • 113
Daniele Cannova
  • 309
  • 3
  • 5
  • I think the solución must be one that does not disturb "normal" users, disable right click will prevent users to copy and paste some text, or search a word they are intersested in, for example un the title of the video,of course not all users will likely do that but It can be anoying for some of them – John Balvin Arias Jun 07 '18 at 04:17
27

As a client-side developer I recommend to use blob URL, blob URL is a client-side URL which refers to a binary object

<video id="id" width="320" height="240"  type='video/mp4' controls  > </video>

in HTML leave your video src blank, and in JS fetch the video file using AJAX, make sure the response type is 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();
}

Note: This method is not recommended for large file

EDIT

  • Use cross-origin blocking and header token checking to prevent direct downloading.

  • If the video is delivered via an API; Use a different http method (PUT / POST) instead of 'GET'

Sajan
  • 813
  • 9
  • 14
  • 4
    YouTube uses Blob now too i think :) ? – C0nw0nk Jul 20 '17 at 22:13
  • 1
    Can you explain what's going on here more clearly and how to set up the server for this? – Anthony Dec 01 '17 at 01:21
  • When you download the blob via XHR, it's just bits in memory. The `createObjectURL` call creates a URL with the `blob:` scheme that can be used in the `src` attribute. The same method works with image files for an `img` tag. Now, keep in mind, whatever method you're using in your JS to generate / validate the XHR, a clever developer could do from the command line to grab your files. You can't *stop* downloads, but you can make them harder. – Coderer Apr 17 '18 at 10:03
  • But you still execute it in client side and xhr.open('GET', 'mov_bbb.mp4', true); could be reached by a user in dev tools – Gleb Dolzikov May 02 '18 at 12:59
  • @dolzikov "normal" users at max will try to see the URL from , I don't think they can continue after that – John Balvin Arias Jun 07 '18 at 04:27
  • 1
    @nerdofcode how does that behave when users try to forward the video? Will they need to wait until all the video download? – John Balvin Arias Jun 07 '18 at 04:31
  • 1
    @JohnBalvinArias! I've not tested this 100%, but I'm going to say that it only needs a quick buffer... Don't quote me on this though... – NerdOfCode Jun 07 '18 at 04:48
  • Sorry for that, I got wrong in who edited and who answered – John Balvin Arias Jun 07 '18 at 05:06
  • 3
    If I inspect the page, in the Network tab I get a request for the video that I can just open in a new tab. – Simone Feb 26 '19 at 08:25
  • @Simone Access-Control-Allow-Origin may help – Sajan Mar 14 '19 at 19:16
  • 1
    Perfect for me! works so good. The only thing that really makes difficult to download a video – Sergio Suarez Sep 03 '19 at 10:22
  • 1
    How do websites do this for large files? Do they segment them first? – Denis Jun 26 '21 at 23:09
  • @Denis Although you split them, you built a custom controllers and implemented some complex code to get partials; This is still not an ideal solution for large files. – Sajan Jun 30 '21 at 09:31
  • by the way what file size is considered a large file in this context. Is an audio file of 5MB can be considered large to be served as a blob? – Munam Yousuf Oct 22 '21 at 21:57
  • 5MB can be considered as a small file, The large, small categorization would depend on the targeted devices, 60MB is a large file for a mobile device but not in MacBookPro. – Sajan Apr 02 '22 at 16:58
13

PHP sends the html5 video tag together with a session where the key is a random string and the value is the filename.

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>'; 

Now PHP is asked to send the video. PHP recovers the filename; deletes the session and sends the video instantly. Additionally all the 'no cache' and mime-type headers must be present.

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:

Now if the user copy the url in a new tab or use the context menu he will have no luck.

B.F.
  • 477
  • 6
  • 9
  • 2
    I like the solution- it solves OPs question. One unfortunate thing is, when the checks the source code in Chrome and right-clicks on the link. The user will download a html file, which in fact will be the video file. – user1252280 Dec 21 '17 at 20:48
12

We could make that not so easy by hiding context menu, like this:

<video oncontextmenu="return false;"  controls>
  <source src="https://yoursite.com/yourvideo.mp4" >
</video>
Jcyrss
  • 1,513
  • 3
  • 19
  • 31
12

You can use

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

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

It doesn't prevent saving the video, but it does remove the download button and the "Save as" option in the context menu.

clickbait
  • 2,818
  • 1
  • 25
  • 61
8

We ended up using AWS CloudFront with expiring URLs. The video will load, but by the time the user right clicks and chooses Save As the video url they initially received has expired. Do a search for CloudFront Origin Access Identity.

Producing the video url requires a key pair which can be created in the AWS CLI. FYI this is not my code but it works great!

$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>';
prophoto
  • 342
  • 3
  • 9
  • 1
    Highly underrated comment. I'd advise using https://docs.aws.amazon.com/sdk-for-php/v3/developer-guide/service_cloudfront-signed-url.html nowadays however. – Zmart Oct 18 '18 at 03:29
  • 1
    If the token expires, does that mean they cannot navigate around the video either? As this seems to contact the video URL again. – Chud37 Apr 05 '19 at 12:27
  • If the video is expired, the user can still watching the video to the end. But I don't think they can jump to different time stamp. When they jump, that's another GET request, which will fail. – iouzzr May 28 '22 at 03:28
7

First of all realise it is impossible to completely prevent a video being downloaded, all you can do is make it more difficult. I.e. you hide the source of the video.

A web browser temporarily downloads the video in a buffer, so if could prevent download you would also be preventing the video being viewed as well.

You should also know that <1% of the total population of the world will be able to understand the source code making it rather safe anyway. That does not mean you should not hide it in the source as well - you should.

You should not disable right click, and even less you should display a message saying "You cannot save this video for copyright reasons. Sorry about that.". As suggested in this answer.

This can be very annoying and confusing for the user. Apart from that; if they disable JavaScript on their browser they will be able to right click and save anyway.

Here is a CSS trick you could use:

video {
    pointer-events: none;
}

CSS cannot be turned off in browser, protecting your video without actually disabling right click. However one problem is that controls cannot be enabled either, in other words they must be set to false. If you are going to inplament your own Play/Pause function or use an API that has buttons separate to the video tag then this is a feasible option.

controls also has a download button so using it is not such a good idea either.

Here is a JSFiddle example.


If you are going to disable right click using JavaScript then also store the source of the video in JavaScript as well. That way if the user disables JavaScript (allowing right click) the video will not load (it also hides the video source a little better).

From TxRegex answer:

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

Now add the video via JavaScript:

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

Functional JSFiddle


Another way to prevent right click involves using the embed tag. This is does not however provide the controls to run the video so they would need to be inplamented in JavaScript:

<embed src="https://www.w3schools.com/html/mov_bbb.mp4"></embed>
Xantium
  • 11,201
  • 10
  • 62
  • 89
  • 1
    Adding the src URL via JavaScript is not much useful. Inspecting the DOM will show the URL in plain sight after the script set it. – Simone Feb 26 '19 at 08:14
  • @Simone I agree, however it is better than showing it directly in the html source, where anybody that right clicks it can see it immediatly. You could always split up the url or encrypt it. But remember that is additional processing – Xantium Feb 26 '19 at 11:37
  • 2
    "CSS cannot be turned off in browser" - Technically you can modify the CSS in web browser developer tools to disable certain CSS rules, so a more tech-savvy person could remove `pointer-events: none;` – Phil Gibbins Apr 21 '20 at 09:26
6

You can at least stop the the non-tech savvy people from using the right-click context menu to download your video. You can disable the context menu for any element using the oncontextmenu attribute.

oncontextmenu="return false;"

This works for the body element (whole page) or just a single video using it inside the video tag.

<video oncontextmenu="return false;" controls>...</video>
TxRegex
  • 2,347
  • 21
  • 20
6

well, you can't protect it 100% but you can make it harder. these methods that I'm explaining, I faced them during studying protection methods in PluralSight and BestDotNetTraining. nevertheless, none of these methods stopped me from downloading what I want, but I had a hard time to curate the downloader to pass their protection.

In addition to other mentioned methods to disable the context menu. the user still is able to use third-party tools like InternetDownload manager or other similar software to download the videos. the protection method that I'm explaining here is to mitigate those 3rd party software.

the requirement of all of these methods is to block a user when you identify someone is downloading your videos. in this way they are able to download only one or two videos only before you banned them from accessing to your website.

disclaimer

I will not accept any responsibility if someone abuses these methods or use it to harm others or the websites that I mentioned as an example. it's just for sharing knowledge to help you to protect your intellectual product.

generate links with an expiry

the requirement for this is to create a download link per user. that one can easily be handled by azure blob storage or amazon s3. you can create a download link with twice of the video length expiry timestamp. then you need to capture that video link and the time that is requested. this is necessary for the next method. the catch for this method is you are generating the download link when the user click the play button.

on play button event you will send a request to the server and get the link and update the source.

throttle the video request rate

then you monitor how fast the user request for the second video. if the user request for a download link too fast, then you block them right away. you can't put this threshold too big because you can mistakenly block users that are just browsing or skimming through the videos.

Enable HTTP Range

use some js library like videojs to play your video, also you need to return an AcceptRange in your header. Azure blob storage supports this out of the box. this way the browser starts to download the video chunk by chunk. usually, 32byte by 32byte. then you need to listen to videojs timeupdate change and update your server about the percentage that the video is watched. the percentage that the video is watched can't be more than the percentage that video is delivered. and if you are delivering a video content without receiving any percentage change, then you can block the user. because for sure they are downloading.

implementing this is tricky because the user can skip the video forward or backwards so be conscious about this when you are implementing this.

this is how BestDotnetTraining is handling the 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);
            }
        });
    }

});

anyway, the user is able to work around this by using some download method that downloads a file through streaming. almost c# do it out of the box and for nodejs, you can use request module. then you need to start a stopWatch, listen to a package received and compare the total byte received compare to the total size. this way you can calculate a percentage and the time spent to get that amount of percentage. then use the Thread.Sleep() or something like that to delay the thread the amount that you have to wait if you watch the video normally. also before the sleep the user can call the server and update the percentage that is received. so the server thinks that the user is actually watching a video.

the calculation will be something like this, for example, if you calculate that you received 1 per cent so far, then you can calculate the amount that you should wait to sleep the download thread. in this way you can't download a video faster than what it's actual length is. if a video is 24 min. it will takes 24 min to download it. (plus the threshold we put in the first method)

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

check the browser agent

when you are serving a webpage and serving the video link or accepting the progress update request you can look at the browser agent. if it's different then ban the user.

just be aware that some old browser doesn't pass this information. so you should ignore this when there is no browser agent in both video request and webpage request. but if one request has it and another one doesn't, then you should ban the user.

to work around this the user can set the browser agent header manually same as the headless browser that they are using to capture the download link.

check the referer header

when the referer is something other than your host URL or the page URL that you are serving the video, you can ban the user, because they put the download link in another tab or another application. even you can do that for the progress update request.

the requirement for this is to has a mapping of video and the page that shows that video. you can create some convention or pattern to understand what the URL should be, it's up to your design.

to work around it the user can set the referrer header manually equal to the download page URL when downloading the videos.

Calculate the time between request

if you receive so many requests that the time between them is the same, then you should block the user. you should put this to capture how much is time between the video link generation request. if they are the same (plus/minus some threshold) and it happens more than a number of times, then you can ban the user. because if there is a bot that is going to crawl your website or videos, then usually they have the same sleep time between their request. so if you receive each request, for example, every 1.3(plus/mins some deviation) minutes. then you raise an alarm. for this, you can use some statistic calculation to know the deviation between the requests.

to workaround this, the user can put a random sleep time between the requests.

sample code

I have a repo PluralSight-Downloader that is doing it halfway. I created this repo almost 5 years ago. because I wrote it for study purpose and own personal use only, the repo isn't received any update so far and I'm not going to update or make it easy to work with. it's just an example of how it can be done.

Mohammad Hossein Amri
  • 1,842
  • 2
  • 23
  • 43
5

The

<body oncontextmenu="return false;"> 

no longer works. Chrome and Opera as of June 2018 has a submenu on the timeline to allow straight download, so user doesn't need to right click to download that video. Interestingly Firefox and Edge don't have this ...

kendolew
  • 386
  • 4
  • 6
3

Using a service such as Vimeo: Sign in Vimeo > Goto Video > Settings > Privacy > Mark as Secured, and also select embed domains. Once the embed domains are set, it will not allow anyone to embed the video or display it from the browser unless connecting from the domains specified. So, if you have a page that is secured on your server which loads the Vimeo player in iframe, this makes it pretty difficult to get around.

user2771704
  • 5,994
  • 6
  • 37
  • 38
3

+1 simple and cross-browser way: You can also put transparent picture over the video with css z-index and opacity. So users will see "save picture as" instead of "save video" in context menu.

Alex Babak
  • 489
  • 3
  • 15
2

Here's what I did:

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>
This also works for images, text and pretty much anything. However, you can still access the "Inspect" and the "View source" tool through keyboard shortcuts. (As the answer at the top says, you can't stop it entirely.) But you can try to put barriers up to stop them.
Calum Childs
  • 337
  • 2
  • 12
2

Here's a complete solution for disabling download including right click > Save as... in the context menu:

<video oncontextmenu="return false;" controlsList="nodownload">
</video>
Koby Douek
  • 16,156
  • 19
  • 74
  • 103
2

Try this for disable download Video options

<video src="" controls controlsList="nodownload"></video>
Muthulakshmi M
  • 651
  • 7
  • 8
1

Short Answer: Encrypt the link like youtube does, don't know how than ask youtube/google of how they do it. (Just in case you want to get straight into the point.)

I would like to point out to anyone that this is possible because youtube does it and if they can so can any other website and it isn't from the browser either because I tested it on a couple browsers such as microsoft edge and internet explorer and so there is a way to disable it and seen that people still say it...I tries looking for an answer because if youtube can than there has to be a way and the only way to see how they do it is if someone looked into the scripts of youtube which I am doing now. I also checked to see if it was a custom context menu as well and it isn't because the context menu is over flowing the inspect element and I mean like it is over it and I looked and it never creates a new class and also it is impossible to actually access inspect element with javascript so it can't be. You can tell when it double right-click a youtube video that it pops up the context menu for chrome. Besides...youtube wouldn't add that function in. I am doing research and looking through the source of youtube so I will be back if I find the answer...if anyone says you can't than, well they didn't do research like I have. The only way to download youtube videos is through a video download.

Okay...I did research and my research stays that you can disable it except there is no javascript to it...you have to be able to encrypt the links to the video for you to be able to disable it because I think any browser won't show it if it can't find it and when I opened a youtube video link it showed as this "blob:https://www.youtube.com/e5c4808e-297e-451f-80da-3e838caa1275" without quotes so it is encrypting it so it cannot be saved...you need to know php for that but like the answer you picked out of making it harder, youtube makes it the hardest of heavy encrypting it, you need to be an advance php programmer but if you don't know that than take the person you picked as best answer of making it hard to download it...but if you know php than heavy encrypt the video link so it only is able to be read on yours...I don't know how to explain how they do it but they did and there is a way. The way youtube Encrypts there videos is quite smart so if you want to know how to than just ask youtube/google of how they do it...hope this helps for you although you already picked a best answer. So encrypting the link is best in short terms.

1

controlsList Prevent action such as download begin fullscreen without adding any other JavaScript function

   <video width="400"  controlsList="nofullscreen nodownload"  controls>
Arun AL
  • 128
  • 2
  • 5
0

It seems like streaming the video through websocket is a viable option, as in stream the frames and draw them on a canvas sort of thing.

Video streaming over websockets using JavaScript

I think that would provide another level of protection making it more difficult for the client to acquire the video and of course solve your problem with "Save video as..." right-click context menu option ( overkill ?! ).

Community
  • 1
  • 1
Guy
  • 1,254
  • 17
  • 16
0

If you are looking for a complete solution/plugin, I've found this very useful https://github.com/mediaelement/mediaelement

Matteus Barbosa
  • 2,409
  • 20
  • 21
0

Prevent HTML5 video from being downloaded (right-click saved)

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

You can't.

For example, people can use some APIfor example desktopCapture, getUserMedia that allows users to record screen, window, tab.

People can use it and write it to the canvas and then concatenate all the chunks together to get the video,

So there is no way to stop them from downloading the video if they really want it.

Carson
  • 6,105
  • 2
  • 37
  • 45
0

I found a good answer to a similar problem, using PHP instead of JavaScript for better security.

I want to play test.mp4 in the user's browser using the browser's default player (just as though URL/test.mp4 had been clicked on a Web page), but requiring a password, which is either supplied by the user or internally by software.

Here is a brief sketch of the idea. It starts with the user going to (running) a program I wrote called secure.php to play test.mp4.

The file test.mp4 is in a subdirectory ("secureSubdirectory") that contains a .htaccess containing "Require all denied". This immediately prevents any direct access through a URL.

When secure.php is run, it supplies a password (or queries the user for a password), then does a POST to itself that includes the password, verifies it using a salt, using the PHP commands:

$Hash=base64_encode(hash_hmac("sha256",$Pwd,$Salt,true));
$HashesAreSame=hash_equals($Hash,$GoalHash);

then tests for test.mp4 existing, and executes the following PHP code to return the test.mp4 file as a byte stream to the user's browser:

header("Content-Type: video/mp4");
echo file_get_contents("secureSubdirectory/$path");
exit;

The video shows as expected. If I then right-click on the page showing the video and try saving the video, the resulting file will just contain an error string, like "Error: password not found", since test.mp4 is being queried using the plain secure.php URL, not through POST with the correct password.

Of course, you can obtain the response payload (the video bytes) using the Network option of the browser debugging tools, but this could be prevented by the PHP program or the .htaccess file if the browser provided an option to prevent access to the debugging tools.

I can't imagine a failure case, but I'd be very interested if one exists, as simple but perfect authorization is a very rare thing. (Note that, since this method relies on a password, associating it with the user is not a secure way to authenticate, since the user can accidentally or deliberately publish or share the password.)

David Spector
  • 1,520
  • 15
  • 21
-1

@Clayton-Graul had what I was looking for, except I needed the CoffeeScript version for a site using AngularJS. Just in case you need that too, here's what you put in the AngularJS controller in question:

    # 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

"strange things are afoot at the circle k" (it's true)

Ryan Crews
  • 3,015
  • 1
  • 32
  • 28
-1

Everything you see in the browser is downloaded content. The question being alluded to is how to save that content in the browser. To view content, client browsers download from content servers and make it available locally.

One solution becoming popular is to save (ephemeral) content in browser only, and for a limited time, in a way that cannot be saved directly. Blobs are one implementation of this with the added benefit of reducing bandwidth & storage overheads, since the content is stored in binary objects.

The short expiry of content makes persistent storage almost impossible to ordinary users since new content is displayed before user can attempt to save expired content.

Zimba
  • 2,854
  • 18
  • 26