Mask URL Plugin for CPG 1.5.x Mask URL Plugin for CPG 1.5.x
 

News:

CPG Release 1.6.26
Correct PHP8.2 issues with user and language managers.
Additional fixes for PHP 8.2
Correct PHP8 error with SMF 2.0 bridge.
Correct IPTC supplimental category parsing.
Download and info HERE

Main Menu

Mask URL Plugin for CPG 1.5.x

Started by gmc, April 19, 2015, 06:21:37 AM

Previous topic - Next topic

0 Members and 3 Guests are viewing this topic.

gmc

OK... I owed the dev team this one for a while now...
We've talked about ways to better secure your photos in the gallery - as the path to your photos is clearly visible in the html source produced by the gallery. So here is an alternative - the ability to 'mask' or 'encrypt' the filepath in the produced URLs.
There is of course a tradeoff between more secure and more overhead... read on.

This plugin adds the  ability to mask or hide the actual file location of your pictures...
Normally the delivered html contains <img> tags that can be read to find your photo locations and directory structure.
As the photos are delivered via <img> tags, http access must be provided to the album folder (and subfolders).
This allows curious (or malicious) users an easy opportunity to find your pictures and download them.
But what if the delivered html looked like this:

  <img src="index.php?file=maskurl/displayimage&photokey=8dOgllfG1PqJQwj0%2BNuSOMuDNKC%2B14ABd6Rfn7nhZNXVaB9bn0V1IOUTZ%2FGw" ...>

Since the path to the albums directory is configurable (doesn't have to be 'albums/') and of course you can have any subfolder structure you
want... the task of locating your pictures files is made harder... to near impossible (based on your choices configuring the plugin).

Options to 'mask' or 'encrypt' the path to photos are offered.
These options appear to have similar results - but the algorithm used has quite different results.

  • The masking can be decoded by anyone that can read/understand the PHP being used (access to this plugin's source) - but it does have less overhead.
  • The encryption requires encryption keys and initialization vectors that would require access to specific fields in your Coppermine database in addition to the PHP code to be able to reverse. The encryption option will use more CPU resources - but provides better protection.
The choice is of course yours...

An additional benefit if masking/encrypting is that http access to the albums directory is no longer required... All CPG functions generating the picture URL drive this plugin, and all will be changed.  As a result, a .htaccess file can be placed in the albums directory denying all access - providing additonal protection for your photos. A sample .htaccess file is included in the plugin directory - named .htaccess.txt - this needs to be copied to the albums directory and named .htaccess if you wish to use it.
NOTE: If you disable this plugin - or set the option to 'Clear Text' - and have the .htaccess file in place, you will be unable to view photos in your gallery!!

All filetypes permitted by CPG are supported (based on the contents of cpg15x_filetypes table). Proper additions to that table will be automatically recognized by the plugin and supported. The 'mime' type must be correctly specified in that table!

The readme file can be viewed at: (also included in the zip file of course...):
http://greggallery.gmcdesign.com/plugins/maskurl/readme.php

The results:
I've been using this technique in my gallery for some time... using the encryption option and the .htaccess restriction.
http://gallery.gmcdesign.com
Can you tell me where my photos are?

Code is attached below.

Good luck, and let me know what you think...
Thanks!
Greg (gmc on the cpg forum)
Thanks!
Greg
My Coppermine Gallery
Need a web hosting account? See my gallery for an offer for CPG Forum users.
Send me money

marcelm

When trying to activate the plug-in I get the following error:

Fatal error: Call to undefined function mcrypt_get_key_size() in /var/www/site/plugins/maskurl/functions.php on line 31

marcelm

Installed now php-mcrypt and php-phpseclib-crypt-rijndael and the plug-in still not want to install.

I got some warnings on installing crypt-Rijndael

  Installing : php-process-5.4.40-1.el6.remi.x86_64                                                                   1/6
  Installing : php-xml-5.4.40-1.el6.remi.x86_64                                                                       2/6
  Installing : 1:php-pear-1.9.5-10.el6.remi.noarch                                                                    3/6
  Installing : php-channel-phpseclib-1.3-1.el6.remi.noarch                                                            4/6
  Installing : php-phpseclib-crypt-base-0.3.10-1.el6.remi.noarch                                                      5/6
PHP Warning:  popen() has been disabled for security reasons in /usr/share/pear/OS/Guess.php on line 242
PHP Warning:  fgets() expects parameter 1 to be resource, null given in /usr/share/pear/OS/Guess.php on line 243
PHP Warning:  pclose() has been disabled for security reasons in /usr/share/pear/OS/Guess.php on line 252
  Installing : php-phpseclib-crypt-rijndael-0.3.10-1.el6.remi.noarch                                                  6/6
PHP Warning:  popen() has been disabled for security reasons in /usr/share/pear/OS/Guess.php on line 242
PHP Warning:  fgets() expects parameter 1 to be resource, null given in /usr/share/pear/OS/Guess.php on line 243
PHP Warning:  pclose() has been disabled for security reasons in /usr/share/pear/OS/Guess.php on line 252
  Verifying  : php-phpseclib-crypt-base-0.3.10-1.el6.remi.noarch                                                      1/6
  Verifying  : php-channel-phpseclib-1.3-1.el6.remi.noarch                                                            2/6
  Verifying  : php-xml-5.4.40-1.el6.remi.x86_64                                                                       3/6
  Verifying  : php-phpseclib-crypt-rijndael-0.3.10-1.el6.remi.noarch                                                  4/6
  Verifying  : php-process-5.4.40-1.el6.remi.x86_64                                                                   5/6
  Verifying  : 1:php-pear-1.9.5-10.el6.remi.noarch 

marcelm

After the reboot of the server the plug-in stalled fine. Selecting other than 'clear text' hides all my thumbnails and that is maybe due to that that I am using an other plug-in EnlargeIt.

gmc

Quote from: marcelm on April 19, 2015, 12:19:00 PM
After the reboot of the server the plug-in stalled fine. Selecting other than 'clear text' hides all my thumbnails and that is maybe due to that that I am using an other plug-in EnlargeIt.
I installed EnlargeIt to test - and there is a conflict...

EnlargeIt replaces the <img> tags via filter 'theme_display_thumbnails_params' overwriting any changes made earlier by the 'picture_url' filter...  So all the image thumb and normal URLs appear in clear text on the thumbnails page even when mask_url has encrypted them...
And since it replaces the <img> tages - it now needs http access to the albums folder...
So if you have the .htaccess rules in place in the albums directory - the thumbnails will display fine on the main page - but when selecting an album, the thumbnails will fail to load (as requested by .htaccess).

The cost of security...  :(
I'll take a deeper look to see what can be done - as I know EnlargeIt is a popular plugin

@devs - can a plugin call the pluginAPI??  Just a thought...
Thanks!
Greg
My Coppermine Gallery
Need a web hosting account? See my gallery for an offer for CPG Forum users.
Send me money

allvip

Great plugin.
Is this going to stop HTTrack Website Copier to download the entire gallery?

marcelm

Quote from: allvip on April 19, 2015, 08:24:20 PM
Is this going to stop HTTrack Website Copier to download the entire gallery?
No, but it will make them using more storage space to keep sequential version because the names differ each iteration.

gmc

Quote from: allvip on April 19, 2015, 08:24:20 PM
Great plugin.
Is this going to stop HTTrack Website Copier to download the entire gallery?
If it drives the link in the html (which will drive the script to unencrypt) then they will get the file (and it appears to in a quick test... )  I'll have to see how usable the resulting site is (running a mirror now).
It certainly won't have the folder structure in the albums directory that it would have without the plugin.

Bottom line - Really can't stop someone from downloading a file that you make visible to the www. You can make it harder or more inconvenient - but if you made it visible - it can (and will) be downloaded by HTTrack, a browser, etc...
HTTrack by default presents itself with a user agent identifying itself - and observes robot.txt restrictions - but both can be easily overridden by the user.

What it stops is them being able to download files you DON'T make visible... ie - your original (fullsize) photos if you only allow viewing of thumbnail and intermediate.
If I know Coppermine's naming, and the path to your thumbnail... I can request the larger photo directly from the filesystem normally.  THIS action is made much more difficult (I tend not to say impossible as the world keeps making better hackers) - as they won't know the path to follow to begin with, and even if they knew the path - the .htaccess (if in place in albums to 'Deny from all') would stop them.

Quote from: marcelm on April 19, 2015, 09:19:29 PM
No, but it will make them using more storage space to keep sequential version because the names differ each iteration.
Well... each time you change encryption keys (refreshable in config) - they will think everything is new... it should get ugly for them quickly if you regularly change keys...  Wouldn't be hard to have a cron script change keys even just once a day to drive their storage use much higher... :)
Thanks!
Greg
My Coppermine Gallery
Need a web hosting account? See my gallery for an offer for CPG Forum users.
Send me money

marcelm

Maybe you an use/rewrite the SEF support that is available in EnlargeIt.

Link to the SEF plugin: http://forum.coppermine-gallery.net/index.php/topic,42568.0.html

ron4mac

Quote from: gmc on April 19, 2015, 09:48:24 PM

Well... each time you change encryption keys (refreshable in config) - they will think everything is new... it should get ugly for them quickly if you regularly change keys...  Wouldn't be hard to have a cron script change keys even just once a day to drive their storage use much higher... :)
How about using a cookie key for masking/encryption that could be different for each page load, making the urls different every time?

gmc

Quote from: gmc on April 19, 2015, 02:54:39 PM
I installed EnlargeIt to test - and there is a conflict...

EnlargeIt replaces the <img> tags via filter 'theme_display_thumbnails_params' overwriting any changes made earlier by the 'picture_url' filter...  So all the image thumb and normal URLs appear in clear text on the thumbnails page even when mask_url has encrypted them...
And since it replaces the <img> tages - it now needs http access to the albums folder...
So if you have the .htaccess rules in place in the albums directory - the thumbnails will display fine on the main page - but when selecting an album, the thumbnails will fail to load (as requested by .htaccess).

The cost of security...  :(
I'll take a deeper look to see what can be done - as I know EnlargeIt is a popular plugin

@devs - can a plugin call the pluginAPI??  Just a thought...

I've posted some changes in the EnlargeIt thread that make it compatible with Mask Url - and likely any other plugin that uses the 'picture_url' filter.
EnlargeIt was recreating the thumbnail URL from scratch rather than using what may have been changed by plugins.  It was also creating new URL's for intermediate or fullsize photos - and no one else had a chance to change..

I altered the enlargeit_addparams in that plugin's codebase.php to:

  • respect any thumbnail URL changes previously made
  • invoke the pluginAPI for filter 'picture_url' after generating the intermediate/fullsize URL
(appeared to be no issue with a plugin driving the pluginAPI... as long as we don't get into a recursion issue... :) )

See this thread for details:
http://forum.coppermine-gallery.net/index.php?topic=57424.msg378225#msg378225

Greg
Thanks!
Greg
My Coppermine Gallery
Need a web hosting account? See my gallery for an offer for CPG Forum users.
Send me money

ron4mac


gmc

#12
Quote from: ron4mac on April 20, 2015, 03:59:36 PM
How about using a cookie key for masking/encryption that could be different for each page load, making the urls different every time?
Interesting idea... thinking that through a bit.

How do googlebots react to cookies? would they still be able to crawl the site - or would the picture loads all fail? (some may view that as good - others as bad...)
Right now a user doesn't need cookies enabled to view a gallery (unless restricted to registered users).

What additional protection would it provide? The user has already downloaded the picture (to view the page) - so they have the image...  What does it prevent at that point?

Does it provide any more protection than an nightly cron job that refreshes the encryption keys? (even the value of that is limited I think...)

The real protection here is not knowing the path to photos to go 'fishing' for more than is allowed... ie - if I disallow access to fullsize - without this masking/encryption the user knows the folder structure - and knows the name of the intermediate picture... finding the fullsize isn't rocket science...
This protection is accomplished even if the keys NEVER change.

As a side note to earlier comments - I did some testing with HTTrack - and while they do get a navigable copy - the entire album directory structure is missing - with all picture files as indexxxx.jpg in the root directory...
Changing keys on every page load would drive that process crazy (maybe a good thing.. :) ) as they would download the same pic repeatedly for every page it appeared on.... meta albums, random pics, album, etc...) each thumb and fullsize would look like a different URL to them...

I don't have an issue adding more options. The intent was to allow the gallery owner to pick the degree of protection (and degree of overhead) they wanted/needed...

I should be able to use an early plugin hook to optionally generate the IV (init vector) - store as a cookie that could then be read by each invocation to display... (The IV would get combined with the encryption key in the DB to successfully unencrypt...  Currently both are in the DB.
Two simultaneous page loads from the same browser might get interesting - but the timing window is quite small between setting and reading the cookie.

Additional thoughts welcome...
Have a couple of changes already in V1.1 that I can add to before releasing.

Quote from: ron4mac on April 20, 2015, 07:38:58 PM
I also modified my slideshow plugin to be compatible with MaskUrl.
http://forum.coppermine-gallery.net/index.php/topic,75994.0.html
GREAT!  thanks... I'll download that and give it a try too.

Greg
Thanks!
Greg
My Coppermine Gallery
Need a web hosting account? See my gallery for an offer for CPG Forum users.
Send me money

gmc

From the input so far... and anticipating some additional input... V1.1 is now attached to the first post in thread.

The additions:
Added validation of encryption functions, requested algorithm and mode to install to prevent install failure
- plugin will initialize, but will disable encryption support (masking support still available)
- config messages will indicate failure and show requested and available support
- specify 'Refresh Encryption Keys' to redrive initialization
(avoids install problem noted by marcelm - when encryption wasn't available)

Added 4th mask option - Encrypt URL with Dynamic IV
- new initialization vector for every page load - URL for same image will be different on every page load
- IV sent to client as cookie and retrieved to decrypt
(suggestion from ron4mac for use of dynamic keys)

Add configuration parms for encryption algorithm and mode - selectable via config page
- options dynamic based on installed algorithms and modes on your webserver

Add configuration parm for OS type, initially populated by PHP_OS constant - but overrideable.
- used by maskurl_encrypt_keys to take alternate actions for windows platform required if php version < 5.3

Add configuration parm for URL format, by default (internal) driving normal CPG initialization
- default is incompatible with plugins like EnlargeIt *IF* using 'Encrypt URL with Dynamic IV'
- select 'external' URL format for alternate format that works with EnlargeIt. 

Happy encrypting...  :)
Greg
Thanks!
Greg
My Coppermine Gallery
Need a web hosting account? See my gallery for an offer for CPG Forum users.
Send me money

marcelm

Works great with my site (Blankstraped). The Dynamic IV will show the first picture from my slider but the second one I get a endless wait.

I noticed also that one of my albums was not show and it workes out that I have spaces in directory name and that is maybe the cause of that it is not being show.

Will also install the adapted version of Slideshow by ron4mac later today.

My site is: www. mmmfotografie. nl

Many thanks for this great plug-in!

gmc

Quote from: marcelm on April 22, 2015, 11:14:18 AM
Works great with my site (Blankstraped). The Dynamic IV will show the first picture from my slider but the second one I get a endless wait.
Did you try the new option to "Use 'external' URL format"?  With Dynamic IV - any interaction with CPG will regenerate the IV for that session (new cookie) - rendering all previous URLs that client has unusable... The 'external' URL format does NOT drive normal CPG initialization - and may allow the slider to work (it worked with EnlargeIt..)
default:

index.php?file=maskurl/displayimage&photokey=9qswIIbX6EWWXbFHPVYWjzYSqKD4CoM%2F3wWXW54rxjocdPEh2yoMMONtooUt204P
external:

plugins/maskurl/displayimage.php?photokey=9qswIIbX6EWWXbFHPVYWjzYSqKD4CoM%2F3wWXW54rxjocdPEh2yoMMONtooUt204P


Quote
I noticed also that one of my albums was not show and it workes out that I have spaces in directory name and that is maybe the cause of that it is not being show.
Yes... the space makes it through encrypt/decrypt - but comes out as a %20 in the <img> tag.
In displayimage.php (the plugins version!), find (in either 1.0 or 1.1):

    $debug_trace[] = "Generated Photopath Prefix: ".substr($photopath, 0, 10);

and insert before:

    $photopath = urldecode($photopath);


Quote
Many thanks for this great plug-in!
You're welcome... glad you like it!

Greg
Thanks!
Greg
My Coppermine Gallery
Need a web hosting account? See my gallery for an offer for CPG Forum users.
Send me money

marcelm

Some times I have to click three times on different pictures to have go into wait.

My error log is showing entries starting with clicking the second picture:

[Wed Apr 22 14:06:26 2015] [error] [client x.x.x.x] PHP Warning:  filesize(): stat failed for ../../plugins/maskurl/sample.jpg in /var/www/site/plugins/maskurl/displayimage.php on line 123, referer: http://www.site.nl/plugins/maskurl/displayimage.php?photokey=6OVkO%2FNZsjemsBdON0WvViMjTRq0jmzXuxhlidLVoICzxJBClRT8GPGk9QjLezXXsLg%3D
[Wed Apr 22 14:06:26 2015] [error] [client x.x.x.x] PHP Warning:  readfile(../../plugins/maskurl/sample.jpg): failed to open stream: No such file or directory in /var/www/site/plugins/maskurl/displayimage.php on line 124, referer: http://www.site.nl/plugins/maskurl/displayimage.php?photokey=6OVkO%2FNZsjemsBdON0WvViMjTRq0jmzXuxhlidLVoICzxJBClRT8GPGk9QjLezXXsLg%3D
[Wed Apr 22 14:07:21 2015] [error] [client x.x.x.x] PHP Warning:  filesize(): stat failed for ../../plugins/maskurl/sample.jpg in /var/www/site/plugins/maskurl/displayimage.php on line 123, referer: http://www.mmmfotografie.nl/plugins/maskurl/displayimage.php?photokey=6OVkO%2FNZsjemsBdON0WvViMjTRq0jmzXuxhlidLVoICzxJBClRT8GPGk9QjLezXXsLg%3D
[Wed Apr 22 14:07:21 2015] [error] [client x.x.x.x] PHP Warning:  readfile(../../plugins/maskurl/sample.jpg): failed to open stream: No such file or directory in /var/www/sit/plugins/maskurl/displayimage.php on line 124, referer: http://www.site.nl/plugins/maskurl/displayimage.php?photokey=6OVkO%2FNZsjemsBdON0WvViMjTRq0jmzXuxhlidLVoICzxJBClRT8GPGk9QjLezXXsLg%3D


My ModSecurity for Apache is also having a go at Photokey but that can loosened in ModSecurity:

[Wed Apr 22 13:57:50 2015] [error] [client x.x.x.x] ModSecurity: Access denied with code 403 (phase 2). Pattern match "(?i)([\\\\s\\"'`;\\\\/0-9\\\\=]+on\\\\w+\\\\s*=)" at ARGS:photokey. [file "/etc/httpd/modsecurity.d/activated_rules/modsecurity_crs_41_xss_attacks.conf"] [line "21"] [id "973337"] [rev "1"] [msg "XSS Filter - Category 2: Event Handler Vector"] [data "Matched Data: 8ONVtVoshWtxGfzfmRe6oW7ftGKq48EHwWdsEADS5qjIVQ= found within ARGS:photokey: wQaZrym5XqYbYw5DApCNI7vBSd Di8ONVtVoshWtxGfzfmRe6oW7ftGKq48EHwWdsEADS5qjIVQ="] [severity "CRITICAL"] [ver "OWASP_CRS/2.2.9"] [maturity "1"] [accuracy "8"] [tag "OWASP_CRS/WEB_ATTACK/XSS"] [tag "WASCTC/WASC-8"] [tag "WASCTC/WASC-22"] [tag "OWASP_TOP_10/A2"] [tag "OWASP_AppSensor/IE1"] [tag "PCI/6.5.1"] [hostname "www.site.nl"] [uri "/plugins/maskurl/displayimage.php"] [unique_id "VTeMvsCoFR4AAH3Zmu0AAAAP"]

The adaptation that ron4mac made in his html4slideshow plug-in to also work with maskURL works great.

marcelm

I have looked into ModSecurity and made a configuration file which disable that specific combination of rule and file.

created a file named 999_user_exclude.conf in the active rules with the content:

<LocationMatch /plugins/maskurl/displayimage.php>
   <IfModule mod_security2.c>
     SecRuleRemoveById 973337
   </IfModule>
</LocationMatch>

<LocationMatch delete.php>
   <IfModule mod_security2.c>
     SecRuleRemoveById 981173
   </IfModule>
</LocationMatch>


LocationMatch is the location of the to ignored file and SecRuleRemoveBtId is the number of the security id which can be found back in the error log of the httpd/apache and you can see such a line in my posting directly above.

Location: [uri "/plugins/maskurl/displayimage.php"]
Security id: [id "973337"]

gmc

Quote from: marcelm on April 22, 2015, 02:22:01 PM
My error log is showing entries starting with clicking the second picture:

[Wed Apr 22 14:06:26 2015] [error] [client x.x.x.x] PHP Warning:  filesize(): stat failed for ../../plugins/maskurl/sample.jpg in /var/www/site/plugins/maskurl/displayimage.php on line 123, referer: http://www.site.nl/plugins/maskurl/displayimage.php?photokey=6OVkO%2FNZsjemsBdON0WvViMjTRq0jmzXuxhlidLVoICzxJBClRT8GPGk9QjLezXXsLg%3D
[Wed Apr 22 14:06:26 2015] [error] [client x.x.x.x] PHP Warning:  readfile(../../plugins/maskurl/sample.jpg): failed to open stream: No such file or directory in /var/www/site/plugins/maskurl/displayimage.php on line 124, referer: http://www.site.nl/plugins/maskurl/displayimage.php?photokey=6OVkO%2FNZsjemsBdON0WvViMjTRq0jmzXuxhlidLVoICzxJBClRT8GPGk9QjLezXXsLg%3D
[Wed Apr 22 14:07:21 2015] [error] [client x.x.x.x] PHP Warning:  filesize(): stat failed for ../../plugins/maskurl/sample.jpg in /var/www/site/plugins/maskurl/displayimage.php on line 123, referer: http://www.mmmfotografie.nl/plugins/maskurl/displayimage.php?photokey=6OVkO%2FNZsjemsBdON0WvViMjTRq0jmzXuxhlidLVoICzxJBClRT8GPGk9QjLezXXsLg%3D
[Wed Apr 22 14:07:21 2015] [error] [client x.x.x.x] PHP Warning:  readfile(../../plugins/maskurl/sample.jpg): failed to open stream: No such file or directory in /var/www/sit/plugins/maskurl/displayimage.php on line 124, referer: http://www.site.nl/plugins/maskurl/displayimage.php?photokey=6OVkO%2FNZsjemsBdON0WvViMjTRq0jmzXuxhlidLVoICzxJBClRT8GPGk9QjLezXXsLg%3D


Well - the image won't display in those cases - but we shouldn't be filling up logs with errors...
(sample.jpg was an image used in the code I based this plugin I based this on... and referenced in the event we encountered an error. An 'old' IV would produce an invalid URL and be changed to sample.jpg.  I didn't include in this plugin as I didn't think it was still used... A better choice in this case is the system nopic..)

for now... in displayimage.php (plugin version)
Find:

$sampleimage = 'plugins/maskurl/sample.jpg';

Replace with:

$sampleimage = 'images/thumbs/thumb_nopic.png';

The next line - $samplethumbimage is not referenced anywhere else...

I'll make this either configurable - or use the system (or theme override) image in the next release.. (opinions welcome...)
Thanks!
Greg
My Coppermine Gallery
Need a web hosting account? See my gallery for an offer for CPG Forum users.
Send me money

marcelm

The thumbnails are displayed in one go however the full size is not. This starts after 'enlarging' the second and consecutive pictures.

I found some code that gets information through the 'du' command and so only for Linux servers:

exec( ( 'du -b "'.__Directory__.escapeshellcmd( $curFolder ).'/"*'), $filenames );
foreach( $filenames as $key => $val )
{
    $size = substr( $val, 0, strpos( $val, '/' ) );
    $filename = substr( $val, strpos( $val, __Directory__ ) + strlen(__Directory__) );
    $filenames[$filename] = $size;
    unset( $filenames[$key] );
}
print_r( $filenames );


This probably not the way to go if you are in a hosted setting with your server.