Setting up image copy protection in 1C-Bitrix

Our company is engaged in the development, support and maintenance of Bitrix and Bitrix24 solutions of any complexity. From simple one-page sites to complex online stores, CRM systems with 1C and telephony integration. The experience of developers is confirmed by certificates from the vendor.
Our competencies:
Development stages
Latest works
  • image_website-b2b-advance_0.png
    B2B ADVANCE company website development
    1175
  • image_bitrix-bitrix-24-1c_fixper_448_0.png
    Website development for FIXPER company
    811
  • image_bitrix-bitrix-24-1c_development_of_an_online_appointment_booking_widget_for_a_medical_center_594_0.webp
    Development based on Bitrix, Bitrix24, 1C for the company Development of an Online Appointment Booking Widget for a Medical Center
    564
  • image_bitrix-bitrix-24-1c_mirsanbel_458_0.webp
    Development based on 1C Enterprise for MIRSANBEL
    747
  • image_crm_dolbimby_434_0.webp
    Website development on CRM Bitrix24 for DOLBIMBY
    655
  • image_crm_technotorgcomplex_453_0.webp
    Development based on Bitrix24 for the company TECHNOTORGKOMPLEKS
    976

Image Copy Protection Configuration in 1C-Bitrix

Competitors copy product photos with the company's watermark — this happens constantly. Completely preventing image downloads is impossible, but you can raise the cost of copying to a level where taking your own photographs becomes easier.

What actually works and what doesn't

Does not work:

  • Right-click blocking via JavaScript (oncontextmenu="return false") — disabled in the browser in 3 seconds
  • CSS pointer-events: none — the image remains accessible through DevTools
  • Blocking via JS dragstart handler — copied through screenshots or the network tab

Works:

  • Watermark applied to the image server-side — difficult to remove if the mark is semi-transparent and centered
  • Serving images via PHP with referer validation — slows down hotlinking
  • Replacing image URLs with an authenticated resource

Watermark via GD

The most practical approach is applying a watermark when an image is uploaded to 1C-Bitrix. Handle the OnAfterFileSave event:

// /local/php_interface/init.php
AddEventHandler('main', 'OnAfterFileSave', ['\Local\Security\WatermarkHandler', 'apply']);
namespace Local\Security;

class WatermarkHandler
{
    private const ALLOWED_DIRS = ['/upload/iblock/', '/upload/catalog/'];
    private const WATERMARK    = '/local/images/watermark.png';

    public static function apply(array $file): void
    {
        $path = $file['PATH'] ?? '';

        // Catalog images only
        $inAllowed = false;
        foreach (self::ALLOWED_DIRS as $dir) {
            if (str_starts_with($path, $_SERVER['DOCUMENT_ROOT'] . $dir)) {
                $inAllowed = true;
                break;
            }
        }

        if (!$inAllowed) return;
        if (!in_array(strtolower($file['CONTENT_TYPE'] ?? ''), ['image/jpeg', 'image/png', 'image/webp'])) return;
        if (!file_exists($path) || !file_exists($_SERVER['DOCUMENT_ROOT'] . self::WATERMARK)) return;

        self::applyWatermark($path, $_SERVER['DOCUMENT_ROOT'] . self::WATERMARK);
    }

    private static function applyWatermark(string $imagePath, string $wmPath): void
    {
        $imgInfo = getimagesize($imagePath);
        if (!$imgInfo) return;

        // Load the source image
        $image = match ($imgInfo[2]) {
            IMAGETYPE_JPEG => imagecreatefromjpeg($imagePath),
            IMAGETYPE_PNG  => imagecreatefrompng($imagePath),
            default        => null,
        };

        if (!$image) return;

        $wm     = imagecreatefrompng($wmPath);
        $imgW   = imagesx($image);
        $imgH   = imagesy($image);
        $wmW    = imagesx($wm);
        $wmH    = imagesy($wm);

        // Scale the watermark to 30% of image width if larger
        if ($wmW > $imgW * 0.3) {
            $ratio = ($imgW * 0.3) / $wmW;
            $newWmW = (int)($wmW * $ratio);
            $newWmH = (int)($wmH * $ratio);
            $resizedWm = imagecreatetruecolor($newWmW, $newWmH);
            imagealphablending($resizedWm, false);
            imagesavealpha($resizedWm, true);
            imagecopyresampled($resizedWm, $wm, 0, 0, 0, 0, $newWmW, $newWmH, $wmW, $wmH);
            imagedestroy($wm);
            $wm   = $resizedWm;
            $wmW  = $newWmW;
            $wmH  = $newWmH;
        }

        // Position: center of the image
        $dstX = (int)(($imgW - $wmW) / 2);
        $dstY = (int)(($imgH - $wmH) / 2);

        imagecopy($image, $wm, $dstX, $dstY, 0, 0, $wmW, $wmH);

        // Save back
        match ($imgInfo[2]) {
            IMAGETYPE_JPEG => imagejpeg($image, $imagePath, 90),
            IMAGETYPE_PNG  => imagepng($image, $imagePath, 7),
        };

        imagedestroy($image);
        imagedestroy($wm);
    }
}

Hotlinking protection via nginx

location ~* \.(jpg|jpeg|png|gif|webp)$ {
    valid_referers none blocked ~\.yourdomain\.com;
    if ($invalid_referer) {
        return 403;
    }
}

Or replace the image on hotlinking:

location ~* \.(jpg|jpeg|png|gif|webp)$ {
    valid_referers none blocked ~\.yourdomain\.com;
    if ($invalid_referer) {
        rewrite ^ /local/images/hotlink-protected.jpg last;
    }
}

Serving images via PHP (for private catalogs)

If images should be available to authenticated users only:

// /local/ajax/secure-image.php
$fileId  = (int)($_GET['id'] ?? 0);
$token   = $_GET['token'] ?? '';

if (!validateImageToken($fileId, $token)) {
    http_response_code(403);
    exit;
}

$file = \CFile::GetFileArray($fileId);
if (!$file) { http_response_code(404); exit; }

$path = $_SERVER['DOCUMENT_ROOT'] . $file['SRC'];
if (!file_exists($path)) { http_response_code(404); exit; }

header('Content-Type: ' . $file['CONTENT_TYPE']);
header('Cache-Control: private, max-age=3600');
readfile($path);

The token is an HMAC of the file ID and a salt: hash_hmac('sha256', $fileId, SECRET_KEY).

Practical recommendations

A watermark works best combined with thoughtful design: a semi-transparent logo centered on the image is harder to remove than a corner one. For high-value items (jewelry, designer furniture) — apply to 100% of images. For a mass catalog with thousands of SKUs — apply only to the main product image. Do not apply watermarks to brand images from suppliers — contracts prohibit it.