3

I have created a folder called secure, inside this folder I have an file .htaccess and the files .mp4

secure
    |--- trailer.mp4
    |--- .htaccess

My file .htaccess

RewriteEngine on

RewriteRule ^(.*)/(.*)/(.*)$ file.php?h=$1&t=$2&v=$3
RewriteRule ^$ - [F]
RewriteRule ^[^/]+\.(flv|mp4)$ - [F]

Through this form I can access the file without any problem, without any error.

$path = "secure/trailer.mp4";
$size=filesize($path);

$fm=@fopen($path,'rb');
if(!$fm) {
  // You can also redirect here
  header ("HTTP/1.0 404 Not Found");
  die();
}

$begin=0;
$end=$size;

if(isset($_SERVER['HTTP_RANGE'])) {
  if(preg_match('/bytes=\h*(\d+)-(\d*)[\D.*]?/i', $_SERVER['HTTP_RANGE'], $matches)) {
    $begin=intval($matches[0]);
    if(!empty($matches[1])) {
      $end=intval($matches[1]);
    }
  }
}

if($begin>0||$end<$size)
  header('HTTP/1.0 206 Partial Content');
else
  header('HTTP/1.0 200 OK');

header("Content-Type: video/mp4");
header('Accept-Ranges: bytes');
header('Content-Length:'.($end-$begin));
header("Content-Disposition: inline;");
header("Content-Range: bytes $begin-$end/$size");
header("Content-Transfer-Encoding: binary\n");
header('Connection: close');

$cur=$begin;
fseek($fm,$begin,0);

while(!feof($fm)&&$cur<$end&&(connection_status()==0))
{ print fread($fm,min(1024*16,$end-$cur));
  $cur+=1024*16;
  usleep(1000);
}
die();

but at the moment of wanting to encrypt the path of the file and decrypt the file file.php does not work for me, it does not open anymore, it does not play the file .mp4.

encrypt.php

<?php
session_start();
$sid = session_id();

$path = "secure/trailer.mp4";

$hash = md5($path.$sid); //You need to use proper encryption. This is not secure at all.

$_SESSION[$hash] = $path;
?>
<html>
<head></head>
<body>
    <video width="320" height="240" controls>
        <source src="file.php?video=<?= $hash ?>" type="video/mp4">
    </video>
</body>
</html>

decrypt in file file.php

<?php
session_start();
if (isset($_GET["video"]) && isset($_SESSION[$_GET["video"]])) {

$file = $_SESSION[$_GET["video"]]; //Get the filename
readfile($file);

$path = $file;
//$path = "secure/trailer.mp4";
$size=filesize($path);

$fm=@fopen($path,'rb');
if(!$fm) {
  // You can also redirect here
  header ("HTTP/1.0 404 Not Found");
  die();
}

$begin=0;
$end=$size;

if(isset($_SERVER['HTTP_RANGE'])) {
  if(preg_match('/bytes=\h*(\d+)-(\d*)[\D.*]?/i', $_SERVER['HTTP_RANGE'], $matches)) {
    $begin=intval($matches[0]);
    if(!empty($matches[1])) {
      $end=intval($matches[1]);
    }
  }
}

if($begin>0||$end<$size)
  header('HTTP/1.0 206 Partial Content');
else
  header('HTTP/1.0 200 OK');

header("Content-Type: video/mp4");
header('Accept-Ranges: bytes');
header('Content-Length:'.($end-$begin));
header("Content-Disposition: inline;");
header("Content-Range: bytes $begin-$end/$size");
header("Content-Transfer-Encoding: binary\n");
header('Connection: close');

$cur=$begin;
fseek($fm,$begin,0);

while(!feof($fm)&&$cur<$end&&(connection_status()==0))
{ print fread($fm,min(1024*16,$end-$cur));
  $cur+=1024*16;
  usleep(1000);
}
die();
}

They can explain to me that I am doing wrong, I try to make the url have a 12 hour validation access, I would like the generation to be through its ip address.

  • I noticed that you are using the code in [this answer](https://stackoverflow.com/a/15798799), but I've tested it and it didn't work well for me. So I tested the code **in the [question](https://stackoverflow.com/q/5924061)** (see the *Solution derived from: http://mobiforge.com/developing/story/content-delivery-mobile-devices*) and the code worked well for me. So I suggest you to try that and if it works, you should answer your own question (i.e. this question). (PS: Sorry, I was unable to test the code when you pointed me to [that](https://stackoverflow.com/q/5924061) question yesterday..) – Sally CJ Apr 10 '19 at 16:54
  • @SallyCJ Hello friend, the code of the question works very well, although it is a bit confusing for all the discussions that have taken place, and the rest of the answer is the same code that I had, I thought it would have no solution. –  Apr 11 '19 at 00:22
  • @SallyCJ Leave the question as it was before, it would be a waste to create more controversy, my fault in not looking for more options. Thank you :). –  Apr 11 '19 at 01:27
  • Just for the record, [this](https://pastebin.com/kzR29gQk) is the code that worked pretty well for me. It's not the same as [this](https://stackoverflow.com/a/15798799) which you used, although they both have same purpose. And you should have invited me to chat when I [asked](https://stackoverflow.com/questions/55545692/how-to-run-plugin-library-when-changing-video/55584680?noredirect=1#comment97895250_55584680) you to.. :) – Sally CJ Apr 11 '19 at 02:09
  • Alright then, let's put that aside. But do you still need help with *this* question ("encrypt and decrypt URL")? Have you tried what's suggested in the current answer? – Sally CJ Apr 11 '19 at 04:22
  • Lou, you haven't replied to my question - do you still need help with this specific question? I'm sure others want to know, too. – Sally CJ Apr 13 '19 at 01:54
  • @SallyCJ I'm sorry I did not answer, I was somewhat busy with no time to access the computer, I've actually searched for information and I've done the following `video.php?expires=1555224592&token=7f2d0ecb3cfcea1f9a280610bf6f8dfd72087c8cfcae90d1422a4bb2e34e77c5&video=40fb6841889315bfbc174742791fe6f1` everything works perfectly, although I'm still using the same code that encodes the file path. –  Apr 13 '19 at 18:52
  • @SallyCJ Really if I would like help on whether this `$hash = md5($path.$sid);` safely encrypts the file path `40fb6841889315bfbc174742791fe6f1` and if not, I would like to learn a little more about correctly secure the path of the file `$path = "secure/trailer.mp4";` –  Apr 13 '19 at 18:56
  • Thanks for your replies, Lou. Now that you have a (perfectly) working soluton, I think you could just use it - and give the bounty to the current answer, because IMHO it is a good answer. And regarding whether the `md5($path.$sid)` "safely *encrypts* the file path", then that's something I'd say, "no", just as the current answer. But if your question was "is it properly *hashed*", then yes, it seems fine - although the hashing could be made "tougher" than simple MD5 of the file path and the current session ID. Nonetheless, use what works best for you. :) – Sally CJ Apr 13 '19 at 20:10

2 Answers2

2

They can explain to me that I am doing wrong, $hash = md5($path.$sid); //You need to use proper encryption. This is not secure at all.

Please try to learn difference between hash and encryption. (I won't explain it, it will be your homework). Regardless that - md5 is completely broken and insecure to use, definitely in this case.

I try to make the url have a 12 hour validation access,

You may have a look how big cloud vendors are creating links with expirable limited access. (try to search how OpenStack or AWS are creating expirable links)

Maybe you even don't need to encrypt the file name, it can be completely satisfying to make sure the authorising application has granted access to the file.

Very simple example:

https://host/filename?expire=<expire timestamp>&signature=<hmac(base)>

where the base could be whatever you need , such as url, client ip, expiration timestamp

if you will need to encrypt the file name, then encrypt it properly, see openssl_encrypt.

gusto2
  • 11,210
  • 2
  • 17
  • 36
0

Actually as it was mentioned above the encryption/description differs from hashing. I have made a simple example based on your code:

includes.php

<?php
function encrypt_decrypt($action, $string)
{
    $output = false;
    $encrypt_method = "AES-256-CBC";
    $secret_key = '<My-secret-key>';

    $ivlen = openssl_cipher_iv_length($string);
    $secret_iv = openssl_random_pseudo_bytes($ivlen);
    $key = hash('sha256', $secret_key);
    $iv = substr(hash('sha256', $secret_iv), 0, 16);
    if ($action == 'encrypt') {
        $output = openssl_encrypt($string, $encrypt_method, $key, 0, $iv);
        $output = base64_encode($output);
    } else if ($action == 'decrypt') {
        $output = openssl_decrypt(base64_decode($string), $encrypt_method, $key, 0, $iv);
    }
    return $output;
}

encrypt.php

<?php
include "includes.php";

$fileInfo = array(
    'filePath' => 'secure/trailer.mp4', //path of the file
    'linkValidTill' => mktime(3, 0, 0, 4, 16, 2019) // till when the link must be active
);

$fileInfoJson = json_encode($fileInfo);

$videoInfo = encrypt_decrypt('encrypt', $fileInfoJson);

?>
<html>
<head></head>
<body>
<video width="320" height="240" controls>
    <source src="file.php?video=<?= $videoInfo ?>" type="video/mp4">
</video>
</body>
</html>

file.php

<?php
include "includes.php";

$contentAccessIsDenied = true;

if (isset($_GET["video"])) {
    $fileInfoJson = encrypt_decrypt('decrypt', $_GET["video"]);
    if ($fileInfoJson !== false) {
        $fileInfo = json_decode($fileInfoJson, true);
        if ($fileInfo['linkValidTill'] > mktime()) {
            if(file_exists($fileInfo['filePath'])){
                $contentAccessIsDenied = false;

                $file = $fileInfo['filePath'];
                readfile($file);

                $path = $file;
                $size = filesize($path);

                $fm = @fopen($path, 'rb');
                if (!$fm) {
                    header("HTTP/1.0 404 Not Found");
                    die();
                }

                $begin = 0;
                $end = $size;

                if (isset($_SERVER['HTTP_RANGE'])) {
                    if (preg_match('/bytes=\h*(\d+)-(\d*)[\D.*]?/i', $_SERVER['HTTP_RANGE'], $matches)) {
                        $begin = intval($matches[0]);
                        if (!empty($matches[1])) {
                            $end = intval($matches[1]);
                        }
                    }
                }

                if ($begin > 0 || $end < $size)
                    header('HTTP/1.0 206 Partial Content');
                else
                    header('HTTP/1.0 200 OK');

                header("Content-Type: video/mp4");
                header('Accept-Ranges: bytes');
                header('Content-Length:' . ($end - $begin));
                header("Content-Disposition: inline;");
                header("Content-Range: bytes $begin-$end/$size");
                header("Content-Transfer-Encoding: binary\n");
                header('Connection: close');

                $cur = $begin;
                fseek($fm, $begin, 0);

                while (!feof($fm) && $cur < $end && (connection_status() == 0)) {
                    print fread($fm, min(1024 * 16, $end - $cur));
                    $cur += 1024 * 16;
                    usleep(1000);
                }


            }
        }
    }
}

if ($contentAccessIsDenied) {
    header("HTTP/1.1 401 Unauthorized");
    die();
}

Here as you can see I have added an extra function which encrypts and decrypts the string which is passed to it as an argument. Here you can change the algorithm, secret key, etc...

I suggest instead of passing a hash to file.php and later check it with the session variable, to pass by a querystring variable all the needed data as an encrypted JSON string. Here in my example I'm passing the file path and the time till which the link is supposed to be work (which your code was not possible to at all as the session variables will be cleared out when the session s finished) and in file.php decrypting it with the same algorithm and secret key.

Please note that this is just a simple example you can base on it to solve your problem.

Zeusarm
  • 1,038
  • 6
  • 14