0

I am trying to secure a byte serving script, written in PHP, mostly taken from http://www.tuxxin.com/php-mp4-streaming/ to protect against linking the video directly and easy downloading. I therefore have placed the video outside the public http-root. The pseudo-streaming itself works perfectly fine.

The pages structure like this:
mysite.com/watchvideo.php:

<video>
  <source src="/media.php?t=<?= $t = Token::generate(); ?>" type="video/mp4">
</video>

mysite.com/media.php:

$token = isset($_GET["t"]) ? $_GET["t"] : "";

if (
    !Token::check($token)
    || $_SERVER["HTTP_REFERER"] !== "mysite.com/watchthisawesomevideo.php"
    ) {
        header("HTTP/1.1 403 Forbidden");
        exit;
}

do_the_byte_range_stuff();              // from tuxxin.com

The Token class simply generates a random string, saves it in the php-session and returns it, respectively when checking compares the parameter to the token stored in $_SESSION.

With this method I have the problem that some browsers, like stock and chrome 47 on Android 4.1.2 seem to hand over the streaming to some different process, therefore losing the HTTP_REFERER (possibly related: android issue 1780). If I unset the token on checking it subsequent requests to media.php get abortet. Same goes if I set a time limit for the token.

Once this is sorted I would hide the video and mirror its content onto a canvas.

What would be suitable security measures to protect against downloading the video file and making media.php inaccessible? I know there can't be absolute protection, but I want to make it reasonably difficult.

Edit: Please note that I am not looking for some form of DRM for the video as I know it could be simply recorded off the screen. I am looking for ways to get the video to the watchvideo-page making it only accessible from there and preventing hotlinking.

WhiteWinterWolf
  • 19,082
  • 4
  • 58
  • 104
YPOC
  • 101
  • 1
  • This is a hard question for us to answer as the definition of "reasonably difficult" is rather unclear. – Neil Smithline Jan 26 '16 at 17:08
  • If the video is being transferred to the client, it's going to be relatively simple to grab the stream of data - Chrome will even let you save the file, even if it arrives through the PHP method above, which seems to be geared up to preventing other sites abusing the original site's bandwidth by embedding the video. It doesn't prevent downloading it at all. – Matthew Jan 26 '16 at 17:14
  • If a client can play the video, he can save the video. You can make it difficult, but there's a lot of ways to bypass your measures. People recording Netflix is a proof of this. – ThoriumBR Jan 26 '16 at 17:48
  • Please don't focus on the video itself, I know you could simply record it off the screen or grab the cache. What I'd like to know is how to handle `media.php`. – YPOC Jan 26 '16 at 17:57
  • So if I'm reading this properly, you want to put an access control on media.php to ensure that the content only gets served through watchvideo.php? – Ohnana Jan 26 '16 at 20:03
  • @Ohnana Correct, but I don't need any user verification. – YPOC Jan 26 '16 at 20:35
  • Possible duplicate of [Are there DRM techniques to effectively prevent pirating?](http://security.stackexchange.com/questions/4637/are-there-drm-techniques-to-effectively-prevent-pirating) – Deer Hunter Jan 26 '16 at 21:46

1 Answers1

1

You can set a cookie when the user requests watchvideo.php, containing a hash of values identifying the client, like user agent, IP address, and so:

<?php
 $ip = $_SERVER['REMOTE_ADDR'];
 $browser = implode(':', $_SERVER['HTTP_USER_AGENT']);
 $userFingerprint = md5($browser . $ip);
 setcookie('userdata', $userFingerprint, time() + 10); //expires in 10 sec
?>

On media.php, you read the cookie back:

<?php
 $ip = $_SERVER['REMOTE_ADDR'];
 $browser = implode(':', $_SERVER['HTTP_USER_AGENT']);
 $userFingerprint = md5($browser . $ip);
 if ($_COOKIE['userdata'] != $userFingerprint) {
    header("HTTP/1.1 403 Forbidden");
    exit;
 }
 do_the_byte_range_stuff();
?>

I used MD5, because I don't care about collisions here, I just want a fast hash. You can go overkill and employ BCrypt or PBKDF2, but you absolutely don't have to.

ThoriumBR
  • 50,648
  • 13
  • 127
  • 142
  • Thank you for your answer, but with this solution there's still the problem that subsequent requests to `media.php` (i.e. buffering) get forbidden and directly opening media.php is possible for 10 seconds. – YPOC Jan 27 '16 at 14:35
  • @YPOC you could set a long lasting cookie on `media.php`, so buffering would not be broken. Opening `watchvideo.php` during this interval could clean the cookie, so the client could only watch one video at a time on one browser. – ThoriumBR Jan 28 '16 at 20:04