How to password protect streaming videos with php - php

What is the best way to password protect quicktime streaming videos using php/.htaccess. They are being streamed using rtsp, but I can use other formats if necessary.
I know how to do authentication with php, but I'm not sure how to setup authentication so that will protect the streaming files urls so that a user can't just copy the url and share it.
Or am I overthinking this and I can just use a normal authentication scheme and place the files in a protected directory?

Both nginx and lighttpd web servers have X-Send-File headers you can return from PHP. So you can do your checks in PHP and then conditionally server out the file.
if (check_user_can_access()){
header('X-sendfile: /path/to/file');
} else {
header('HTTP/1.1 403 Fail!');
}
Lighttpd also has a neat module called mod_secure_download that allows you to programatically generate a URL that will only be valid for a short time period.
Nginx, and possibly lighttpd, allow you to cap the download speed, so you're not sending out streaming data faster than it can be consumed.
Either way, you want to use your web server for serving files. Serving them through PHP is possible, but slow.

Try to use Amazon S3 service, it got it's quirks but it makes sense once you get familiar with it.
There are hooks in their API to achieve temporally URL's that are active for specified time, so you can freely show url to visitor because it won't work 10 minutes or so later.
It's almost trivial thing to do with php (around 15 lines of code), there are a lot of examples on their forums so you dont need to go from scratch and read full documentation on how to achieve this.
What kind of authorization you will do before generate and show links it's up to you.
You can also have it look like it's served from your domain like video.yourdomain.com instead of standard s3 URL's.
Last thing, it's cheap - we payed around 2 US$ for the month of testing and deployment when I uploaded 8 GB and downloaded it 3 times completely and initialized download for around 100 times. The person I was doing this for is so satisfied by price that he wants to move all of his downloadable media to s3.
Now, re reading everything I wrote it looks like commercial/spam but I'm so satisfied with service because I coded everything for audio files earlier, and it took days until everything worked just fine and this took couple of hours to implement (mostly getting familiar with service).

You might want to take a look at:
mod_xsendfile (for apache)
It enables you to internally redirect to a file.
So you could point your download link to checkCredentials.php
<?php
if ( isAuthorised($_POST['user'], $_POST['pass']) ) {
header("X-Sendfile: $somefile");
header("Content-Type: application/octet-stream");
header("Content-Disposition: attachment; file=\"$somefile\"");
exit(0);
} else {
show403('bad credentials');
}
?>
This module is also available for other webservers. If I remember correctly, the idea originally comes from lighttpd, but - as Josh states- is also available for nginx.

First off, it is very easy to spoof a referer. This information is stored in the user's browser, so a user can simply telnet into your server and provide his own referer which matches your domain.
A couple things you could try:
First, more secure, but still spoofable. mod_rewrite provides the ability to check cookies. What you could do is set a cookie when the user visits your website that contains some obscure data. Then, you could modify your RerwriteCond to something like this:
RewriteEngine On
RewriteCond %{HTTP_REFERER} !^$
RewriteCond %{HTTP_COOKIE} obscurename=obscurevalue [NC]
RewriteCond %{HTTP_REFERER} !^http://(www\.)?yourdomain.com/.*$ [NC]
RewriteRule \.(asx¦ASX)$ http://www.yourdomain.com/images/leech.gif [R,L]
Another, better technique would involve working with PHP and mime-types. I'm not sure to what extent this would support streaming content, but I assume it'll work. What you can do is have all your video links point to a .php file (the query string will determine which video has been selected). Then, when a user tries to visit this link, you do something like so:
<?php
// You could also check some sort of session variable
// that is set when the user visits another part of your
// site
if(!isLoggedIn()){
header("Location: errorPage.htm");
exit;
}else{
// Get the name of the file specified
$file = get_file_name($_GET['fileID']);
// Specify the proper mime-type for the data you're sending
// (this may have to change, depending on your situation)
header("Content-type: video/vnd.rn-realvideo");
// Read the file and output it to the browser
readfile($file);
}
?>
From what I read, most servers know which mime-types are streaming mime-types, so the browser should be able to figure out how to handle the streaming file properly.

Related

Which is more efficient: redirecting to an image,or pushing the image through php?

An external party has to use the dynamicly generated images that are used on our site. For that, I created a function that serves the image through a url. E.g. http://test.com/image/$code/$width/$height. So, it finds the image with code $code, resizes it to $width and $height, and then serves the image itself (not the url). The external party can now use <img src="http://test.com/image/$code/$width/$height" />
This is working fine, but of course this is a quite a hit on the server every time it is used, especially if the image is used in newsletters that are sent to 1000s of people.
I can make it a little more efficient by checking if the image is already existing and then returning it without generating it first, of course. But I was also looking at redirection.
So, basically, my question is if it is more efficient to generate/load the image and then serve it, or doing a 301 redirect to the actual image. I know that this also has some drawbacks, most notably needing two requests per image, but I am wondering how that compares to pushing an entire image through php and the image generation process.
Update:
Maybe I should clarify things a bit.
I am interested in server load, not so much in UX. Most probably the latter is worse off by redirecting, as it does the double amount of server requests).
The difference in the two situations is as follows:
Image generation situation:
- Check if image exists. If not, generate.
- Then do this
$path = BASE_PATH."/".$image->Filename;
$mimetype = image_type_to_mime_type(exif_imagetype($path));
header("Content-type: ".$mimetype);
echo readfile($path);
die;
Image redirect situation:
- Check if image exists. If not, generate.
- Then do this
$location = BASE_HREF."/".$image->Filename;
$mimetype = image_type_to_mime_type(exif_imagetype($path));
header('Location: '.$location,true,301); //or maybe a 303 (other)
die;
Obviously, in the second situation php has to do less and apache more (serve 2 files instead of one). In the first situation apache has to do more and php less. So the question is, is the extra work that php has to do more or less than the extra work that Apache has to do?
I don't know, but my gut feeling is that if you're already running a PHP script, then the additional cost of writing some headers and calling readfile() will be trivial.
More importantly, is the file going to be used more than once by the same user?
If so, you could benefit significantly by making the file cacheable. If you redirect to a static file, the web server will automatically take care of the caching. If you serve the file through PHP, you will have to cache it yourself.
To do this, you need to:
Compute a Last-Modified date or an ETag (unique ID).
Check the request headers for an If-Modified-Since: or If-None-Match: header.
Compare the header values against the computed date or ETag.
If your file is newer or doesn't match the ETag (or the request headers don't exist), send a 200 response including the file.
Otherwise, send a 304 response without the file.
In both cases, send the current Last-Modified: or ETag header, and maybe a sensible Expires: header.
First, it is critical that you check to see if the image already exists before you generate the thing. It isn't going to help "a little." Creating a .jpg is a lot more expensive than checking for a filename.
The rest of your question isn't completely clear to me, but I'll try for an answer anyway.
301 redirects aren't generally used for what you're talking about. They're to tell a search spider that a page has moved permanently. Functionally, it doesn't work any differently than a regular redirect.
Moving on, I'm even more confused. "and then serves the image itself (not the url)"
Servers pretty much always serve both. The url tells it which file to send and then it sends the binary data it finds at that URL. And files are always saved somewhere, even if it's just a tmp folder where it will be deleted. Unless you've done something exotic, in which case, ask yourself why you did that.
If the image will never be used again (not even if the same user re-vists the same page) simply send the remote server a link to where the lives in the temporary folder on your server after the image was created. If the image might be re-used, save it somewhere. The local server would be easier and the extra request by the remote won't slow things down a noticeable amount.

Secure documents with PHP

I have a simple login / access control system to secure some restricted pages, but within these pages there are links that need to be secure, i.e. Word documents. Therefore if I keep these resources within the webroot they could accessible via a URL. What is the best method to secure these resources that are within the restricted page. I know I could password protect the folder but the user would then be challenged twice, one for the restricted page and then for the resource link. Any advice ?
You have a few options here, depending on your use-case.
Use PHP to serve the file. Basically, either intercept all attempts to read the file by PHP (using a mod_rewrite rule), or link directly to PHP and put the file(s) below the document root. Then use something like fpassthru to send the file to the browser. Note that you must properly set the content-type headers. Also note that this will eat up a lot of server resources since the server needs to read the entire file in PHP and send it, so it's easy, but not light.
$f = fopen('file.doc', 'r');
if (!$f) {
//Tell User Can't Open File!
}
header('Content-Type: ...');
header('Content-Length: '.filesize('file.doc'));
fpassthru($f);
die();
The main benefit to doing it this way is that it's easy and portable (will work on all servers). But you're trading off valuable server resources (since while PHP is serving the file, it can't be serving another page) for that benefit...
Use the web-server to send the file using something like X-SendFile (Lighttpd), X-SendFile (Apache2/2.2) or X-Accel-Redirect (NginX). So you'd redirect all requests to the file to PHP (either manually or rewrite). In PHP you'd do your authentication. You'd send the Content-Type headers, and then send a header like X-SendFile: /foo/file.doc. The server will actually send the file, so you don't have to (it's far more efficient than sending from PHP natively).
header('Content-Type: ...');
header('X-SendFile: /foo/file.doc');
die();
The main benefit here is that you don't need to serve the file from PHP. You can still do all of your authentication and logging that you'd like, but free up PHP as soon as you start transferring the file.
Use something like mod_secdownload (lighttpd) or mod_auth_token (Apache). Basically, you create a token in PHP when you generate the link to the file. This token is a combination of a MD5 of a secret password combined with the current timestamp. The benefit here, is the URL is only valid for how long you specify in the configuration (60 seconds by default). So that means that the link you give out will only be active for 60 seconds, and then any further attempts to see the content will generate a 400 series error (I'm not positive which off the top of my head).
$filename = '/file.doc';
$secret = 'your-configured-secret-string';
$time = dechex(time());
$token = md5($secret . $filename . $time);
$url = "/downloads/$token/$time$filename";
echo "Click Here To Download";
The main benefit to doing it this way is that there is very little overhead associated with the implementation. But you have to be comfortable with having URLs being valid for a set time only (60 seconds by default)...
Push it off onto a CDN to handle. This is like option #3 (the one above), but uses a CDN to handle the file serving instead of your local server. Some CDNs such as EdgeCast provide a similar functionality where you set a token which expires after a set amount of time. This case will work nicely if you have a lot of traffic and can justify the expense of a CDN. (Note: no affiliation with the linked CDN, only linked because I know they offer the functionality).
As far as how I'd personally do it, I've done all of the above. It really matters what your use-case is. If you're building a system that's going to be installed on shared hosts or multiple different servers which you don't control, stick to the first option. If you have full control and need to save server resources, do one of the other two.
Note: there are other options than these three. These are just the easiest to implement, and most of the other options are similar enough to these to fit into the category...
I haven´t tried it with word documents (only with images), but I would try to serve the document directly from php, see my answer about images.
It would be something like an a tag linking to a php page that serves a Word document as its content type.

Counting how many times a image is being served from server?

I want to count the no. of times a image is being served from our server. I have some images in a website and want to count the no. when these images are showed on web pages(served from the server to my website and if hotlinked). Is there any way to accomplish this. I know php so if there is some way doing it in php it would be really helpful.
advice please
thank you.
Can't you look at your server logs for that?
If you're wanting something beyond parsing server-logs, you'd have to setup a database to manage the list of images, and the number of times they're accessed. Serve the images through a .php script which increments the db value with each request. You could use a flat-file system too, but I prefer the db-solution.
You wouldn't need to worry about the source of your image if you implement .htaccess and apache's mod_rewrite. You could serve url's like this:
http://mysite.com/images/001.jpg
Which would be understood on the server as:
http://mysite.com/images.php?id=001
Thus providing a basis to perform database-actions, and scripted logic.
You can use Microsoft's LogParser to query your server logs using a query something like this:
c:\Program Files\Log Parser 2.2> logparser "select cs-uri-stem, count(*) as Hits from C:\Your\Log\File\Path\ex091002.log where cs-uri-stem like 'imagefilename.jpg' or where cs-uri-stem like 'anotherimage.jpg' group by cs-uri-stem order by Hits DESC" -i:w3c
You can even have it output to a text file or a graph (requires Excel, I believe) if you need something to display on a page. You'll probably have to change the query if you're using Apache logs, not sure.
You should be able to gather this information using the log files and an analytics package. If you are running IIS a really good one to look into (and free for 1 domain) is SmarterTools' SmarterStats. www.smartertools.com
The answers recommending looking in the logs are right. But if for some reason that's not acceptable, it's not hard to configure a php script to handle this.
1) Create a rewrite rule (using mod_rewrite) to transparently rewrite requests to your image to go to a php file instead, with the image's name as a parameter.
2) your php script can log the request, then send out the appropriate MIME type for the image, and dump the real file to the output buffer (this shouldn't be affected by your rewrite rule as long as you load from the file system rather than using a URL stream).

how to make a user restrict to download?

I know this question is silly.
But as per our intelligent Client request, I am not able to answer his question. Any one help for this.
We are building a online tutoring site. where it contains pdf, .ppt, .doc formats files are uploaded for reading as course materials. His (Client) request is that user can read all the contents but they must not download the materials and use this.
That is all the documents must be opened in their browsers.
Is it possible? Any other ideas?
Any other ideas?
Explain to your client that the only way for a document to appear on a user's computer screen is for the document to exist on that user's computer.
In other words, viewing a document involves downloading it. Even supposing the software on the user's computer somehow makes it impossible for the user to directly manipulate an electronic copy of the material, the user can take out a digital camera and take a picture of the screen.
There are ways to make it difficult for the user to save a copy of the file. However, it's likely that this will do more harm (frustrating users) than good (preventing theft).
Some users may want to peruse the material at times when they do not have an internet connection, or may want to copy it onto their mobile device (for instance), but accessing the internet on their mobile device is expensive so they would like to do the download on their computer.
If you send the data to the client the client has effectively downloaded it. You can make this difficult, but not impossible.
The only sure way to prevent downloading is to prevent viewing.
If this is a copyright problem it should be solved with legalese, not software.
Here are some guide-lines you may consider:
Don't put direct link of files such as:
Download
Instead, try to generate your pdf dynamically or put a another encrypted medium for
downloading eg:
Download
2: Don't allow directory browsing, use htaccess file with following commands:
Deny from ALL
3: Not sure, but you may possibly allow file opening this way too:
$filename="/path/to/file.jpg"; //<-- specify the image file
if(file_exists($filename)){
header('Content-Length: '.filesize($filename])); //<-- sends filesize header
header('Content-Type: image/jpg'); //<-- send mime-type header
header('Content-Disposition: inline; filename="'.$filename.'";'); //<-- sends filename header
readfile($filename); //<--reads and outputs the file onto the output buffer
exit; //and exit
}
Note: above is just an example of image not pdf but you can modify it for your needs.
An online site does not necessarily mean it is a web site. You could write a custom client that accesses the data and displays it.
The data would need to be encrypted between the client and the server. It probably should not be sent 'in bulk' either.
The effort associated with developing that is prohibitive.
You could license the software that allows users to read books, page by page, that is part of the Safari Books Online web site.
As best I can tell, they take the pages that they are going to display and turn them into small images. These images look as if they are sent in a random order, and assembled by the browser via javascript.
These tactics won't stop a determined person from getting your clients content... but the effort is unlikely to be worth it.
You could put the docs into Google docs and embed the docs viewer into your site. Of course, there's no stopping people from taking screenshots, copy/pasting text, downloading HTML, etc.
What do you mean by "read" but not "download"?? Do you know that even if you disable cache (which by itself is a bad idea) won't restrict an eaaaasy right-click>view source, "save target as", etc.?
I mean, the best you can have is a flash reader that is harder to save the content from, and that means disabling selection and copying, but anyway, it doesn't forbid anything.
The only way to forbid download is to return HTTP 403 :)

Restrict file access to authorized php users

I've inherited an application with a glaring security hole.
It has session-based security, but file uploads (which are user specific) are not secured in any way and they are stored in the public file tree.
Filenames do not follow any convention as such, making them hard to guess, but the data is sensitive and thus I need to implement a security measure to prevent unauthorized file access.
Moving the location of the files is not really an option, so I'm looking at a htaccess solution to forward requests to a php handler script.
Does anyone have experience in implementing this type of thing or any good alternative solutions? Specific examples of .htaccess syntax greatly appreciated, as I'm struggling in this area.
Don't really understand why moving them isn't an option, since pushing requests for them to a handler means it no longer matters where they're stored. But you're the man on the scene.
.htaccess looks like:
RewriteEngine on
RewriteRule path/to/where/these/files/live/(.*) /handlerscript.php/$1
Then you pick up the remaining file path and name from $_SERVER['PATH_INFO'].
Well, you could make apache parse .jpg file's for a certain folder adding the following to your .htaccess
AddHandler php5-cgi .jpg
then you could set a file of php to parse the request the way chaos was recomending you and doing a certain validation, then just return jpeg headers along with the correct picture u'd like to display
here's an example
<?php
if($validUser)
{
header("Cache-control: No-cache");
header("Pragma: No-cache");
header("Content-Type: image/jpeg");
//correct picture address
$img = imagecreatefromjpeg("2326_b_lil.jpg");
imagejpeg($img);
}
else
{
//code for error image
}
?>
please let me know if you want a more extensive example
I think you may need to write a script that will serve the images, then use htaccess to completely restrict access to the actual images from a browser.
The script can take in the web path to the image, decide if the user has access, then use something like fpassthru to feed an actual image to the browser.
All references to the images would need to be modified, however, to reference the serving script.
So instead of accessing the images with /images/123/5423453245.jpg,
it would be /image.php?images/123/5423453245.jpg
Or something similar to that.

Categories