WebsiteBaker Logo
  • *
  • Templates
  • Help
  • Add-ons
  • Download
  • Home
*
Welcome, Guest. Please login or register.

Login with username, password and session length
 

News


WebsiteBaker 2.13.9 is now available!


R.I.P Dietmar (luisehahne) and thank you for all your valuable work for WB
https://forum.websitebaker.org/index.php/topic,32355.0.html


* Support WebsiteBaker

Your donations will help to:

  • Pay for our dedicated server
  • Pay for domain registration
  • and much more!

You can donate by clicking on the button below.


  • Home
  • Help
  • Search
  • Login
  • Register

  • WebsiteBaker Community Forum »
  • WebsiteBaker Support (2.13.x) »
  • General Help & Support »
  • How to protect images on a "Logged In Only" page
  • Print
Pages: [1]   Go Down

Author Topic: How to protect images on a "Logged In Only" page  (Read 1255 times)

Offline CodeALot

  • Posts: 588
  • Gender: Male
How to protect images on a "Logged In Only" page
« on: August 22, 2025, 04:21:45 PM »
Situation: An image is on a page that you can only access once you're logged in. The images however, are stored in the /Media folder. So in theory, someone who knows the URL, could potentially acces the image file directly, bypassing the login-requirement. Also, crawler software would find all the images in de /Media folder(s). Even those images that you want to be accessible for logged in users only.

How would you prevent this?
Logged

Offline dbs

  • Betatester
  • **
  • Posts: 8924
  • Gender: Male
  • tioz4ever
    • WebsiteBaker - jQuery-Plugins - Module - Droplets - Tests
Re: How to protect images on a "Logged In Only" page
« Reply #1 on: August 22, 2025, 05:11:15 PM »
Hi, the AI of your choice could help you.
e.g.
- a folder with the images in media
- a entry in .htaccess what leads all requests for this folder to a special file
- the special file (e.g. protected_media.php) checks the login status and shows the image(s)

not tested
Logged
https://onkel-franky.de

Offline crnogorac081

  • Posts: 2168
  • Gender: Male
Re: How to protect images on a "Logged In Only" page
« Reply #2 on: August 22, 2025, 06:54:27 PM »
https://forum.WebsiteBaker.org/index.php/topic,16282.msg106825.html

Check this and this

https://forum.WebsiteBaker.org/index.php/topic,17482.0.html
« Last Edit: August 22, 2025, 07:01:23 PM by crnogorac081 »
Logged
Web developer

Offline crnogorac081

  • Posts: 2168
  • Gender: Male
Re: How to protect images on a "Logged In Only" page
« Reply #3 on: August 22, 2025, 07:32:23 PM »
And which modul you use in backend to Make content for this ?
Logged
Web developer

Offline sternchen8875

  • Global Moderator
  • *****
  • Posts: 626
Re: How to protect images on a "Logged In Only" page
« Reply #4 on: August 23, 2025, 01:21:28 AM »

Quote
Situation: An image is on a page that you can only access once you're logged in. The images however, are stored in the /Media folder. So in theory, someone who knows the URL, could potentially acces the image file directly, bypassing the login-requirement. Also, crawler software would find all the images in de /Media folder(s). Even those images that you want to be accessible for logged in users only.

(english)
I'm not sure if I should start by explaining the technical background, but since this is a question every site operator has likely considered, I want to try for the benefit of the community. The best way to do this is with an analogy.

A CMS—or rather, any CMS—is the application layer. At this level, the system handles internal security, manages the internal transport of data, and checks the permissions granted to users.

Its counterpart is the web server, which is the delivery layer. Its job is to serve files that are then read and displayed by the browser using various methods.

A CMS can be as secure as it wants; if the web server isn't, you have open doors. The reverse is also true. The issue of the /media directory being public affects many systems. The main reason for this in the past was likely the desire to display content from /media publicly anyway. As a result, little effort was invested in protecting the source files.

Added to this is a fundamental technical problem: Anything a browser can display can also be "saved" by the visitor.
Method 1: Basic Protection via .htaccess

A first step to make direct access more difficult is an entry in the .htaccess file in the CMS's root directory.

(File types and domain need to be adjusted)
   
Code: [Select]
RewriteEngine On
# Block access if the request for an image is not coming from your own domain.
RewriteCond %{HTTP_REFERER} !^http(s)?://(www\.)?yourdomain.com [NC]
RewriteRule \.(jpg|jpeg|png|gif)$ - [F]

 

This rule prevents direct links to the files or embedding them on external websites. It's a relatively simple task, but it's not a "vault." Several points work against it:

- The HTTP_REFERER can be spoofed.

- If the image is used within the website's content, the visitor already has the file on their computer, for example, in the browser's cache.

Method 2: The Most Secure Approach (Delivery via PHP)

Currently, the most secure method is the one where every file to be delivered must be passed through a PHP script. This script first checks for permissions within the CMS and only then, depending on the outcome, sends the requested file to the browser. The directories where these protected files are stored must, in turn, be completely locked down from direct access using their own .htaccess file (e.g., with Deny from All).

But, and this is the crucial point: What happens after that is no longer in the hands of the CMS or the web server, but in the hands of the visitor. Anything that appears in their browser is then under their control.

---------------------------------------------------------------------------------------------
(german)
Ich bin nicht sicher, ob ich zuerst die technischen Zusammenhänge erklären sollte, aber da es eine Frage ist, über die jeder Webseitenbetreiber schon mal nachgedacht hat, möchte ich es für die Community versuchen. Am besten geht das mit einem bildlichen Beispiel.

Das CMS – oder besser gesagt, jedes CMS – ist die Anwenderebene. Auf dieser Ebene sorgt das System für die interne Sicherheit, prüft den internen Transport von Daten und die erteilten Berechtigungen der Benutzer.

Das Gegenstück ist der Webserver, er ist die Bereitstellungseben e. Seine Aufgabe ist es, Dateien zur Verfügung zu stellen, die mit verschiedenen Methoden vom Browser gelesen und dargestellt werden.

Ein CMS kann so sicher sein, wie es will – ist der Webserver das nicht, hat man offene Türen. Umgekehrt gilt das Gleiche. Die Problematik, dass das /media-Verzeichnis öffentlich ist, betrifft viele Systeme. Der Hauptgrund dafür war wohl in der Vergangenheit, dass man Inhalte aus /media ja auch öffentlich anzeigen möchte. Daher wurde in den Schutz der Quelldateien bisher kaum Arbeit investiert.

Dazu kommt das technische Grundproblem: Alles, was ein Browser darstellen kann, kann vom Besucher auch "gesichert" (gespeichert) werden.
Methode 1: Grundlegender Schutz via .htaccess

Ein erster Schritt, um den direkten Zugriff zu erschweren, ist ein Eintrag in der .htaccess-Datei im Hauptverzeichnis des CMS.

(Dateitypen und Domain müssen angepasst werden)

Code: [Select]
RewriteEngine On
# Zugriff blockieren, wenn die Anfrage für ein Bild nicht von deiner eigenen Domain kommt.
RewriteCond %{HTTP_REFERER} !^http(s)?://(www\.)?deinedomain.de [NC]
RewriteRule \.(jpg|jpeg|png|gif)$ - [F]

Diese Regel sorgt dafür, dass direkte Links auf die Dateien oder die Einbindung auf fremden Webseiten unterbunden werden. Das ist eine relativ einfache Aufgabe, aber eben auch kein "Tresor". Dem stehen mehrere Punkte entgegen:

-  Der HTTP_REFERER kann gefälscht werden.

- Wird das Bild im Inhalt der Webseite genutzt, hat der Besucher es bereits auf seinem PC, z.B. im Cache des Browsers.

Methode 2: Der sicherste Ansatz (Auslieferung per PHP)

Als sicherste Methode gilt aktuell die Variante, bei der jede auszugebende Datei eine PHP-Datei durchlaufen muss. Dieses Skript prüft zuerst die Berechtigungen innerhalb des CMS und sendet erst dann, abhängig vom Ergebnis, die gewünschte Datei an den Browser. Die Verzeichnisse, in denen diese geschützten Dateien liegen, müssen dann wiederum durch eine eigene .htaccess-Datei (z.B. mit Deny from All) komplett für den direkten Zugriff gesperrt werden.

Aber, und das ist der entscheidende Punkt: Was danach passiert, liegt nicht mehr in den Händen des CMS oder des Webservers, sondern in denen des Besuchers. Alles, was in seinem Browser erscheint, kann er dann auch benutzen.
Logged

Offline sternchen8875

  • Global Moderator
  • *****
  • Posts: 626
Re: How to protect images on a "Logged In Only" page
« Reply #5 on: August 23, 2025, 04:37:17 AM »
(english)
Regarding the linked script:

In the form presented there, it serves to check permissions for a protected area that requires a user login. After a successful check via the session, the file linked in the request is delivered to the browser. If the user is not logged in, a 403 error is sent to the browser.

However, the script also has a few shortcomings:

    Biggest Flaw: Directory Traversal
    The method used to prevent "Directory Traversal" is vulnerable and easily bypassed. With simple techniques, it's possible to access files outside of the intended directory—potentially across the entire server.

    Lack of Granular Permissions
    The script does NOT check which user is logged in, only that a successful login has occurred. This means if you have different protected areas for different user groups, you won't get the security you're expecting. However, if there's only one protected area "for all" registered users, this would be acceptable.

    Poor Error Handling
    The error messages lack detail. An "Oups" is not very meaningful for the site administrator. For the visitor, a proper 404 ("Not Found") error would certainly be a better message.

    Performance
    The script uses file_get_contents(). This function reads the entire target file into PHP's memory. This can already cause issues with a single large image file and can severely impact server performance when used for a protected gallery with many concurrent requests.


[german)
Zum verlinkten Skript:

In der dort vorgestellten Form dient es zur Prüfung von Berechtigungen in einem geschützten Bereich, der einen User-Login erfordert. Nach erfolgreicher Prüfung über die Session wird die im Aufruf verlinkte Datei dem Browser zur Verfügung gestellt. Ist der User nicht eingeloggt, wird ein 403-Fehler an den Browser gesendet.

Ein paar Mankos hat das Skript aber auch:

    Größter Schwachpunkt: Directory Traversal
    Die Methode zur Verhinderung von "Directory Traversal" ist anfällig und leicht auszutricksen. Mit einfachen Mitteln ist es möglich, auf Dateien außerhalb des vorgesehenen Verzeichnisses zuzugreifen – potenziell auf dem gesamten Server.

    Fehlende Berechtigungsstufen
    Das Skript prüft NICHT, welcher User eingeloggt ist, sondern nur, ob ein erfolgreicher Login stattgefunden hat. Wer also unterschiedliche, geschützte Bereiche für verschiedene Benutzergruppen nutzt, erhält hier nicht den Schutz, den er sich verspricht. Gibt es aber nur einen geschützten Bereich "für alle" registrierten User, wäre das okay.

    Mangelhaftes Error-Handling
    Die Fehlerausgaben sind nicht detailliert. Ein "Oups" ist für den Verwalter der Seite wenig aussagekräftig. Und auch für den Besucher wäre ein 404-Fehler ("Nicht gefunden") sicherlich eine bessere Aussage.

    Performance
    Das Skript verwendet file_get_contents(). Diese Funktion liest die komplette Zieldatei in den Arbeitsspeicher von PHP. Das kann bereits bei einer einzelnen großen Bilddatei zu Problemen führen und bei einer geschützten Galerie mit vielen Zugriffen die Serverleistung stark beeinträchtigen.


Hier eine verbesserte Version, ausgelegt für ein mit .htaccess geschütztes Verzeichnis /media/private. Geprüft wird nur eine korrekte Anmeldung, ausreichend für eine einzelnen geschützten Bereich

Example (The script does NOT check which user is logged in, only that a successful login has occurred)

(english)
Explanation:

    Location of secure_file.php: I have placed this file in the /media directory. If you choose a different location, remember to adjust the path to the config.php file accordingly.

    This solution requires a /private/ folder to be created as a subfolder within /media.

    Protect this 'private' folder with an .htaccess file (code provided below). Test your setup by trying to access a file in this folder directly in your browser; the expected response is a "403 - Forbidden" error.

    Currently, only the image formats *.gif, *.png, *.jpeg, and *.webp are permitted. If you need to allow other file types, you must add them to the script's whitelist.

    If something doesn't work, enable the debug mode in the script (change false to true) and then access the link to the image directly in your browser to see the error message.

Usage / Implementation:

In CKEditor - source code view:
Code: [Select]
<img alt="" class="img-responsive" height="473" src="http://wb1620/media/secure_file.php?file=tiger1.webp" style="" width="760">
In a gallery module, for example:
$image = WB_URL.'/media/secure_file.php?file='.$aGalleryItem['path'].$file;

Important Note: Due to the .htaccess protection in the /media/private folder, the thumbnail preview function for files in ckeditor within this protected folder will not work in some file browsers (like the one in CKEditor). Since every user can have a different folder structure, a universal fix for this is not practical. This functionality would only be possible if this technique were integrated directly into the CMS core.

A temporary workaround is to either rename the .htaccess file in the private folder or to comment out the deny directive within it while you are working.

(german)
Erklärung:
- Dateiablage der secure_file.php: bei mir im media-Verzeichnis - bei Änderung Pfad zur config.php beachten
- erfordert einen Ordner /private/ als Unterordner von /media
- diesen Ordner 'private' mit einer .htaccess schützen (Code siehe unten) - prüfe mit Direktaufrufen einer Datei im Browser, erwartete Antwort ein 403 - Forbidden
- aktuell sind nur Grafikformate *.gif, *.png, *.jpeg und *.webp erlaubt. Bei weiteren Dateitypen bitte ergänzen
- sollte etwas nicht funktionieren, den Debug-Mode in der Datei einschalte (true statt false), Link zum Bild direkt im Browser aufrufen


Aufruf bzw Anwendung
im CKEditor - Quelltext
Code: [Select]
<img alt="" class="img-responsive" height="473" src="http://wb1620/media/secure_file.php?file=tiger1.webp" style="" width="760">
in einer Galerie z.b. so
$image = WB_URL.'/media/secure_file.php?file='.$aGalleryItem['path'].$file;

Hinweis: durch den Schutz mit der .htaccess im /media/private-Ordner funktioniert aktuell die Vorschaufunktion im Ckeditor in diesem geschützten Ordner nicht. Da nun jeder eine andere Ordnerstruktur haben kann oder haben wird, hilft da ein Fix auch nicht. Das ginge nur, wenn man diese Technik gleich ins CMS integriert

Abhilfe würde die temporäre Umbenennung der .htaccess im private-Ordner bringen oder ein Auskommentieren der deny Anweisung


Datei: secure_file.php


Quote
<?php
// =========== DEBUGGING-SCHALTER ===========
// debug mode true or false (show's debug message in direct call
$debug = false;
// ------------------------------------------

// load config.php
require(__DIR__ . '/../config.php');

// build frontend object
if (!isset($wb) || (isset($wb) && !($wb instanceof \frontend))) {
    $wb = new \frontend();
}

// set error report method
if ($debug) {
    error_reporting(E_ALL);
    ini_set('display_errors', 1);
}

// is logged in or not
if ($wb->is_authenticated()) {

    // read path from link
    if (empty($_GET['file'])) {
        http_response_code(400); // Bad Request
        die('Error: No file specified.');
    }
    $requestedFile = urldecode($_GET['file']);
   
    $prefix = 'media/private/';
    if (strpos($requestedFile, $prefix) === 0) {
        $requestedFile = substr($requestedFile, strlen($prefix));
    }
   
    $fileName = basename($requestedFile);
    // build the correct path
    $filePath = WB_PATH . '/media/private/' . $fileName;
    // security check - file must be inside of protected folder
    $realBasePath = realpath(WB_PATH . '/media/private');
    $realFilePath = realpath($filePath);

    if ($realFilePath === false || strpos($realFilePath, $realBasePath) !== 0) {
        if ($debug) die("DEBUG: Zugriff verweigert! Pfad ungültig. Gesucht wurde: " . htmlspecialchars($filePath));
        header("HTTP/1.0 403 Forbidden");
        die("Access Denied");
    }

    // Whitelist for filetypes, add more, if needed
    $allowedTypes = ['image/gif', 'image/png', 'image/jpeg', 'image/webp'];
    $mimeType = mime_content_type($realFilePath);

    if (in_array($mimeType, $allowedTypes)) {
       
        if (!$debug) {
            header("Content-Type: " . $mimeType);
            header("Content-Length: " . filesize($realFilePath));
            header("Content-Disposition: inline; filename=\"" . basename($realFilePath) . "\"");
            header("Cache-Control: private, no-cache, must-revalidate");
            header("Pragma: no-cache");
            ob_clean();
            flush();
            readfile($realFilePath);
            exit();
        } else {
            // show debug messages
            echo "<b>DEBUG-MODUS: Success!</b><br>";
            echo "This script is working:<br>";
            echo "<b>path:</b> " . htmlspecialchars($realFilePath);
            die();
        }

    } else {
        if ($debug) die("DEBUG: forbidden filetype!");
        header("HTTP/1.0 403 Forbidden");
        die("File type not allowed.");
    }

} else {
    // if not authenticated, send 403-error
    if ($debug) die("DEBUG: not authenticated!");
    header('HTTP/1.0 403 Forbidden', TRUE, 403);
    die('<!DOCTYPE HTML><html><head><title>403 Forbidden</title></head><body><h1>Forbidden</h1><p>You don\'t have permission to access this file.</p></body></html>');
}
?>


Example for .htaccess to protect a folder (for Apache 2.4 and (fallback) older

Code: [Select]
# for Apache 2.4 and newer
Require all denied

# for Apache 2.2 and older (Fallback)
<IfModule !mod_authz_core.c>
  Order Deny,Allow
  Deny from all
</IfModule>



P.S.: works with images in a protected folder /media/private


« Last Edit: August 23, 2025, 04:51:14 AM by sternchen8875 »
Logged

Offline CodeALot

  • Posts: 588
  • Gender: Male
Re: How to protect images on a "Logged In Only" page
« Reply #6 on: August 23, 2025, 01:46:05 PM »
Thank you all for the great suggestions! I have my work cut out :-)
Logged

Offline sternchen8875

  • Global Moderator
  • *****
  • Posts: 626
Re: How to protect images on a "Logged In Only" page
« Reply #7 on: August 23, 2025, 03:40:34 PM »
i add this to my Todo-list for the next WB-Version (maybe december or january) and have now a intern function with permissions control for logged users.
My idea: we add a /private/-Folder as subfolder from /media, protected with a .htaccess-file
a central controller works in our index.php in root-folder sends every request to the segret folder to a function

works fantastic in my test, but i've to talk with the others first about this

why not the method from my last posting?
it has no permission control for users
Logged

Offline crnogorac081

  • Posts: 2168
  • Gender: Male
Re: How to protect images on a "Logged In Only" page
« Reply #8 on: August 23, 2025, 06:04:52 PM »
I could Make a ckeditor plugin
Logged
Web developer

Offline CodeALot

  • Posts: 588
  • Gender: Male
Re: How to protect images on a "Logged In Only" page
« Reply #9 on: August 24, 2025, 04:23:58 PM »
Quote from: crnogorac081 on August 23, 2025, 06:04:52 PM
I could Make a ckeditor plugin
That would be wonderful already, although I am more looking for 'protected' MiniGallery-albums. But I understand it will be very complicated to get this to work.
Logged

Offline sternchen8875

  • Global Moderator
  • *****
  • Posts: 626
Re: How to protect images on a "Logged In Only" page
« Reply #10 on: August 24, 2025, 04:27:26 PM »
its complex, but not realy complicated.

i'll work on a patch for this, but will send it first to crnogorac081

give us some hours  ;-)
« Last Edit: August 24, 2025, 04:55:13 PM by sternchen8875 »
Logged

Offline sternchen8875

  • Global Moderator
  • *****
  • Posts: 626
Re: How to protect images on a "Logged In Only" page
« Reply #11 on: August 24, 2025, 11:18:26 PM »
Quote from: CodeALot on August 24, 2025, 04:23:58 PM
I am more looking for 'protected' MiniGallery-albums.

do you use the Minigallery from here or the version from Ruud?
Logged

Offline sternchen8875

  • Global Moderator
  • *****
  • Posts: 626
Re: How to protect images on a "Logged In Only" page
« Reply #12 on: August 24, 2025, 11:43:05 PM »
and i need the used WB-Version, important for the image-handling inside the gallery
Logged

Offline CodeALot

  • Posts: 588
  • Gender: Male
Re: How to protect images on a "Logged In Only" page
« Reply #13 on: August 25, 2025, 10:27:08 AM »
Quote from: sternchen8875 on August 24, 2025, 11:43:05 PM
and i need the used WB-Version, important for the image-handling inside the gallery

I use Ruud's version and WB 2.13.8
Logged

Offline sternchen8875

  • Global Moderator
  • *****
  • Posts: 626
Re: How to protect images on a "Logged In Only" page
« Reply #14 on: August 25, 2025, 11:02:13 AM »
thx
there are a lot of things to change in den Minigallery, because, the integraded uploader use the media-directory for the upload and search for the folder "media/minigal2"
Maybe, it works, if the media-directory is the protected folder, and not a 'private'-Folder inside of 'media'
Logged

  • Print
Pages: [1]   Go Up
  • WebsiteBaker Community Forum »
  • WebsiteBaker Support (2.13.x) »
  • General Help & Support »
  • How to protect images on a "Logged In Only" page
 

  • SMF 2.0.19 | SMF © 2017, Simple Machines
  • XHTML
  • RSS
  • WAP2