Need: protect originals and/or protect some derivatives (e.g. make it imppossible to retrieve the images if we are not authorized)
Condition: use .htaccess (otherwise it would be complicated to move directories from a location non accessible to the browser to a location accessible and vice versa; also update database would be required)
A. Protect originals
- a global config option. If true there will be an htaccess with deny from all in galleries and upload dirs. The functions SrcImage::get_url and get_element_url will always return an url like action.php?id=....
B. Derivatives.
As a reminder, the url of a derivative can be either a php script (i.php) or directly the derivative itself. Depending on wether we want to protect derivatives and rewrite engine is available, we could imagine the following combination of cases
1. No protection, no rewrite
If the derivative has not been generated then the url MUST be the script otherwise It COULD be the php script (slower) or the derivative itself.
2. No protection, rewrite
In all cases the derivative url COULD be the php script or the derivative itself. (requires a htaccess Rewrite which internally redirects to the script if the file does not exist). Always using the the derivative itself url is good for the search engine and optimal because the php script is not invoked if not required.
3. Protection, no rewrite
The derivative url MUST be the php script. htaccess should contain deny from all
4. Protection, rewrite
The derivative url COULD be the php script or the derivative itself. htaccess should contain rewrite rules. For example
#redirect all XLarge and XXLarge to the script for checking the permissions RewriteRule ^galleries/.+-(xl|xx).+$ i.php?/$0 [L] #redirect all other to the script if they don't exist RewriteCond %{REQUEST_FILENAME} -f RewriteCond %{REQUEST_FILENAME} -d RewriteRule ^galleries/.+$ i.php?/$0 [L]
Any other ideas ? Which are we choosing ?
Offline
At configuration level, I would like to replace the piwigo_user_infos.enabled_high by piwigo_user_infos.max_size, set to "original" by default. If the user only has "medium", then she can't see the L, XL, XXL and original sizes.
I had in mind that directories for originals (upload and galleries) would be "deny from all" with .htaccess (or equivalent with Lighttpd/Nginx) and the same for local/i and that the image URL would always be i.php/... but your proposition based on RewriteRule is great. I've been turning it in my my head and I don't see where it fails :-)
I agree with that:
Always using the the derivative itself url is good for the search engine and optimal because the php script is not invoked if not required.
ie if Rewrite is possible, then Piwigo makes things better (and Piwigo can work with Rewrite disabled)
Let's see in details this RewriteRule:
#redirect all XLarge and XXLarge to the script for checking the permissions RewriteRule ^galleries/.+-(xl|xx).+$ i.php?/$0 [L]
I suppose that Piwigo is in charge of writing the .htacess, right? Then Piwigo can automaticaly know what is the threshold to use for RewriteRule: if the minimum max_size among all users is "medium", then the RewriteRule becomes:
#redirect all Medium and bigger sizes to the script for checking the permissions RewriteRule ^galleries/.+-(me|la|xl|xx).+$ i.php?/$0 [L]
Of course, it's a bit useless to use i.php because most of the time the user can see the Large size, and then i.php is not useful, but .htaccess is common to all visitors. Do you agree with that?
PS: this new feature is really exciting, I believe users will highly appreciate it.
Offline
plg wrote:
At configuration level, I would like to replace the piwigo_user_infos.enabled_high by piwigo_user_infos.max_size, set to "original" by default. If the user only has "medium", then she can't see the L, XL, XXL and original sizes.
Perfect, but what about custom resizes ?
here is how a generated .htaccess would be:
#has rewrite, no protection, always use derivative urls for search engines <IfModule mod_rewrite.c> RewriteCond %{REQUEST_FILENAME} -d [OR] RewriteCond %{REQUEST_FILENAME} -f RewriteRule ^.*$ - [L] RewriteRule ^(.*)$ ../../i.php?/$0 [L,QSA] </IfModule> #has rewrite, partial protection of xl,xx, always use derivative urls for search engines <IfModule mod_rewrite.c> RewriteCond %{REQUEST_FILENAME} -d [OR] RewriteCond %{REQUEST_FILENAME} -f RewriteCond %{REQUEST_FILENAME} !^(.*)-(xl|xx)[a-zA-Z0-9_.]*$ RewriteRule ^.*$ - [L] RewriteRule ^(.*)$ ../../i.php?/$0 [L,QSA] </IfModule> #has rewrite, full protection <IfModule mod_rewrite.c> RewriteRule ^(.*)$ ../../i.php?/$0 [L,QSA] </IfModule> #no rewrite - NEED url_style = script for partial or full protection deny from all
Offline
rvelices wrote:
Perfect, but what about custom resizes ?
Do you mean a custom resize generated by a theme? (I don't know yet how to deal with that, at permission level)
Offline
plg wrote:
Do you mean a custom resize generated by a theme? (I don't know yet how to deal with that, at permission level)
Yes. This is the reason why admins must choose a minimum derivative size for watermarking instead of selecting small/medium etc...
Offline
rvelices, do you think it's possible to have such a protection for Piwigo 2.5 maybe? I mean that "upload", "galleries" and "_data/i" directories are "deny from all" and photos are only sent through i.php ?
Offline
plg wrote:
rvelices, do you think it's possible to have such a protection for Piwigo 2.5 maybe? I mean that "upload", "galleries" and "_data/i" directories are "deny from all" and photos are only sent through i.php ?
Possible yes, but it should be customizable and not on by default. Also expect issues / demands such as
- .htaccess issues (file permission, server not being able to parse ...)
- for movies, it will be very bad to send everything to action.php (apache is able to send ranges and you can use forward/backward in some players)
- some people moved the location of _data/i AND/OR galleries AND/OR uploads -> expect complicated issues when generating relative paths from/to root to/from these locations
If someone wants to do it ... go for it ...
Offline
I like to see a solution for private albums. It is not needed for every public photo.
Last edited by Kalle (2012-09-22 09:07:31)
Offline
Just to inform that Gallery sets such a protection : htaccess to [Github] gallery3 file modules/gallery/controllers/file_proxy.php their i.php
it's far from being obvious because i.php will need to check the permissions anyway (user access, size)!
Offline
ultraclub wrote:
2) PROBLEM with such URLs is that we cannot provide in e,g. WIKI direct URL to e.g. project C section in mantis.
why is this? May be exists solution?
If not, what you think about such feature request for mantis?
Sorry but I absolutely don't understand what you said
The features has been implemented in 2.5
Offline
In my experience of protecting content and content access based on permissions, the best and truly only secure way is to have the content outside of docroot. Of course this means you have to serve the content via php (or some other method that streams it). I have in the past been involved in this for image, video, and audio files.
As much as I like Piwigo (I've been playing with for a couple of weeks) I really would have loved to use it but the inability to secure content is killer for my project. It is a subscription site with over 60,000 images and about 2,000 video and audio files. All are owned by individual users so the content needs to be secure. Currently the site is using gallery2 which I have to admit handles security better than on other gallery software I've evaluated (that being said it has all kinds of other problems).
Again because I would love to be able to use Piwigo I would be more than happy to get involved with this project. I can be emailed at gsrtek@gmail.com
Offline
garyR wrote:
Currently the site is using gallery2 which I have to admit handles security better than on other gallery software I've evaluated
Gary, this topic has been discussed many times regarding Piwigo and other Gallery software.
One thing that comes out of all the discussions is that as long as something is displayed on Screen, it can be copied using 'Screen Capture/Recording' software and there is no full proof way to prevent images/video that is allowed to be displayed in a browser been hijacked.
How close to 'protecting' the content does Gallery2 get - and how does that compare to what you can achieve using Piwigo?
Offline
I am sure it comes up a lot (as it is important for some sites), yes anything that can be displayed can be copied. The point is to never display it and keep it out of the docroot so it can not be linked to. In fact for images it is very straight forward, it's bit more difficult for media but I have methods for both.
The following is for an image it was written using Zend Framework but it really doesn't matter what you use.
/**
* Sends full size image back to client
*
* @param Zend_Controller_Request_Http $request
* @param Zend_Controller_Response_Http $response
*
* @return full size image
*/
public function full(Zend_Controller_Request_Http $request, Zend_Controller_Response_Http $response) {
$id = $request->getParam('id');
$locater = new Application_Model_DbTable_ContentLocator();
$locate = $locater->content($id);
// Get the file which has to be here as we are coming from a thumbnail of it
// return it raw
$bits = @file_get_contents($locate->location);
$response->setHeader('Cache-Control', 'public', true);
$response->setHeader('Content-type', 'image/jpeg', true);
$response->setBody($bits);
}
The interesting part is that using this type of logic you can store an image anywhere I have used it with database blobs.
I've also attached the same method except for downloading an image (it is better documented)
public function download(Zend_Controller_Request_Http $request, Zend_Controller_Response_Http $response) {
// id of requested content
$id = $request->getParam('id');
// get a contentLocator object
$contentLocator = new Application_Model_DbTable_ContentLocator();
// get all the information we nee for the content
// content locator is guaranteed to always return a valid location
// if the content is not found the default "Image Not Found" image is returned
$contentLocation = $contentLocator->content($id);
// supress errors as there should not be any
$bits = @file_get_contents($contentLocation->location);
// set the headers and return the image
$response->setHeader('Cache-Control', 'public', true);
$response->setHeader('Content-Disposition: attachment;filename=' . "\"{$contentLocation->name}\";", true);
$response->setHeader('Content-type', 'image/jpeg', true);
$response->setBody($bits);
}
Also Application_Model_DbTable_ContentLocator() constructor optionally can take a Permissions($userId, $contentId) object which is an abstract object that the locator uses to decide if the requester has the appropriate permissions to perform certain actions (ie: view, edit, delete, etc). The locator then returns either the requested image or an appropriate image with an error message. All very neat and clean and easily extensible.
Food for thought
Last edited by garyR (2013-09-14 18:26:09)
Offline