【问题标题】:protect images from being copied保护图像不被复制
【发布时间】:2013-09-23 03:16:27
【问题描述】:

我正在寻找可靠的解决方案来防止图像被复制.. 我的客户(摄影师)希望避免客户在不购买的情况下复制她的照片。

我正在考虑混合使用这些技术:


PHP自制过期

图像是从读取图像文件的 php 脚本加载的,在请求中我捆绑了请求时间戳和文件名。如果时间戳非常接近实际时间戳(两个时间戳都在同一台服务器上生成,因此没有时间配置问题),则在页面生成时创建请求。例如:在生成的 html 中,我有一些 img 标签,例如:

所以当用户想要从源代码中复制图像源时,image.php 脚本不会响应,因为页面生成和图像请求之间存在延迟...

无缓存

如果我发送无缓存标头,我想浏览器不会在客户端计算机上缓存/存储文件?


现在这是基本的想法.. 用户没有原始文件名,因此无法直接访问它们。 有了这个解决方案,我什至可以即时为它们加水印或调整它们的大小

用户仍然可以打印屏幕,有两种类型的打印屏幕,将它们放在剪贴板中的,以及保存文件的。

是否有解决方案,我正在考虑某种 javascript 端 onkeydown 并检测打印屏幕触摸,或在 mac 组合上使用 shift+alt+cmd+[1-4] 并在采取任何操作之前将图像清空.. 这可能吗,或多或少可靠?如何?

我的另一个部分想法是在间隔或某些操作时清除剪贴板,但这对人们来说很烦人,不适用于桌面保存的屏幕截图,并且可能不适用于所有浏览器。

还有其他想法吗?

那么从这里去哪里呢? 这是一个实际的问题,我知道人们毕竟可以为他们的屏幕拍照或使用 hdmi 电缆来捕捉设备。但说真的,这有点矫枉过正,没有人会为这样的照片这样做,我们不是在谈论绝密机密文件……

【问题讨论】:

  • 添加水印,你无法阻止用户将图片从网站上移走。
  • 没有可靠的方法来保护图像。如果图像显示在浏览器中,您可以复制它。你可以让它变得更难一些,但它总是有可能的。
  • 水印和其他故意的人工制品确实是唯一的选择。如果有人可以看到图片,他们可以复制图片。无论您在代码中付出什么努力,他们总是可以截取屏幕截图。
  • 对样本使用带水印的低分辨率图像。当他们购买图像时,他们会获得全分辨率图像。
  • (相关轶事)...我曾经为一家处理医疗数据的公司提供咨询,他们想要一个类似的系统。用户应该能够看到文档和其他数据,但不能复制它们。 (不是一个网站,一个智能客户端应用程序,所以不同的技术。)他们与另一家公司签订了这部分合同,在解决方案上花费了 7 位数,并对他们拥有的东西感到非常自豪。演示时,我拿出手机拍了一张屏幕照片。数据...复制。他们不喜欢那样。

标签: javascript php html image


【解决方案1】:

可以捕获任何显示的内容。所有解决方案都来自服务器端:添加水印,或使用低分辨率的小图像进行显示。

【讨论】:

    【解决方案2】:

    一般的经验法则是:如果可以通过浏览器访问,则用户已经拥有对它的完全访问权限,如果他们愿意,可以使用它。示例选项:

    选项 1:

    防止通过 JavaScript 右键单击​​。

    当用户:

    • 禁用 JavaScript 并刷新页面。
    • 使用截图工具。
    • 手动检查您的 HTML 并找到 img src。

    选项 2:

    将图片作为div的背景图片。

    当用户:

    • 使用截图工具。
    • 手动检查您的 HTML/CSS 并找到 img src。

    选项 3:

    使用水印和/或低分辨率图片。

    这可能是最好的方法。如果您的客户是想要保护他/她的作品的摄影师,那么显示低分辨率图像并提供购买高分辨率版本的选项/链接可能是最好的做法。添加水印也可能会阻止访问者免费拍摄图像,因为没有人愿意在中间有摄影师徽标的照片进行构图。

    【讨论】:

    • 如果使用flash(最好是加密数据流),除了截屏有什么解决办法吗?
    • @JanDvorak 那里有 swf 反编译器。
    • 如果我发现闪存使用 HTTPS 或 Diffie-Hellmann,那么我需要一个实时调试器或闪存小程序将接受的证书 - 或重新实现/端口/重用解码阶段(这可能并不容易) - 或者在中间拉起一个完整的人。
    【解决方案3】:
    1. 摄影师大多在拍高质量的照片,所以为什么不在网站上展示低质量的照片并在上面写“Demo”之类的。
    2. 使用 flash 防止用户复制它们。
    3. 将您的图像编码为 base64 并使用 canvas 或 svg 显示。

    【讨论】:

    • base64 是个坏建议。我可以很容易地偷走那个
    • 它不是完美的解决方案,这是真的。但大多数用户无法窃取,除非他们是技术用户。
    • 我很确定截屏不需要太多技术知识——#2 和 #3 都容易受到影响。不过,我承认,技术含量低的用户通常不知道如何捕获 HTTP 流并对其进行解码。
    【解决方案4】:

    没有 100% 的保护..

    客户总是可以从图像中制作例如屏幕截图。 或者可以使用浏览器的代码检查器获取到图像的链接。

    添加水印是最好的解决方案。

    【讨论】:

      【解决方案5】:

      这是我的实现:

      在 php 生成页面期间首先调用图像时:

      $reqinfo['id'] = $data[id];
      $reqinfo['maxsize'] = 320;
      $reqinfo['timestamp'] = time();
      $reqinfo['base'] = false;
      
      $encoded = base64_encode(openssl_encrypt(serialize($reqinfo), 'AES-128-CBC', 'martine',0,'fgrgfvcfghtfdrfg'));
      
      echo'<div class="imagecontainer"><img src="photo.php?info='.$encoded.'" /></div>'; 
      

      这已经在 imagecontainer 类的 css 和 javascript 中实现了一些限制。 我发送图像 ID(或名称)最大宽度或高度以及请求时间戳,所有这些都在发送到 photo.php 的请求字符串中加密 如果 image 可以绕过所有内容并像普通图像一样被调用,则 base 是正确的。

      照片.php

      <?
      //request info
      $reqinfo = unserialize(openssl_decrypt(base64_decode($_GET[info]), 'AES-128-CBC', 'martine',0,'fgrgfvcfghtfdrfg'));
      
      //image expired
      if(time() - $reqinfo[timestamp] > 10){ exit(); }
      
      //public image
      if($reqinfo[base] == true){ readfile('img/'.$reqinfo[id].'.jpg'); exit(); }
      
      //header cache
      header("Cache-Control: no-cache, must-revalidate"); // HTTP/1.1
      header("Expires: Sat, 26 Jul 1997 05:00:00 GMT"); // Date in the past
      header('Content-type: image/jpeg');
      
      //check cache existance and send out
      if(file_exists( 'img/'.$reqinfo[id].'_'.$reqinfo[maxsize].'.jpg')) { readfile('img/'.$reqinfo[id].'_'.$reqinfo[maxsize].'.jpg'); exit(); }
      
      //source Image
      $image_path = 'img/'.$reqinfo[id].'.jpg';
      list($original_width, $original_height)= getimagesize($image_path); 
      $srcImage = imagecreatefromjpeg( $image_path );
      $ratio = $original_height/$original_width;
      
      
      //create destination image holder
      $destination_width = $reqinfo['maxsize'];
      if($destination_width < 1) $destination_width = 1;
      if($destination_width > $original_width)$destination_width = $original_width;
      $destination_height = round($destination_width*$ratio);
      if ($destination_height > $reqinfo['maxsize'])
      {
          $destination_height = $reqinfo['maxsize'];
          $destination_width = round($destination_height/$ratio);
      }
      $targetImage = imagecreatetruecolor( $destination_width, $destination_height );
      imagealphablending($targetImage,true);
      
      //resample copy logo
      imagecopyresampled( $targetImage, $srcImage, 
      0, 0, 
      0, 0, 
      $destination_width, $destination_height, 
      $original_width, $original_height );
      
      
      // watermark
      $watermark = imagecreatefrompng('watermark.png');
      imagesettile($targetImage, $watermark);
      imagefilledrectangle($targetImage, 0, 0, $destination_width, $destination_height, IMG_COLOR_TILED);
      
      
      
      
      //output
      imagejpeg(  $targetImage, 'img/'.$reqinfo[id].'_'.$reqinfo[maxsize].'.jpg' );
      imagejpeg(  $targetImage );
      imagedestroy( $targetImage );
      
      
      ?>
      

      'martine' 是一个简单的密码 img 显然是非公共路径

      希望这或多或少清楚,基本上是这样(按顺序):

      • 解密 $reqinfo 数组
      • 检查 imagerequest 是否新鲜,如果用户复制 url 并在另一个框架中加载,则不会加载任何图像。
      • 检查图像是否可以绕过调整大小和水印并发送到浏览器
      • 检查是否存在缓存版本以加快进程
      • 重新创建调整大小的版本
      • 添加水印
      • 保存服务器缓存版本
      • 发送“一次性”图片

      希望这可以帮助某人...

      【讨论】:

        猜你喜欢
        • 2023-03-12
        • 2017-10-20
        • 1970-01-01
        • 1970-01-01
        • 2014-06-02
        • 1970-01-01
        • 1970-01-01
        • 2011-09-05
        • 2018-03-24
        相关资源
        最近更新 更多