前端截图身份溯源

发表于 2年以前  | 总阅读数:637 次

背景

今天在跟同事朋友聊这个脉脉上的一些事,我就突然想到之前很多人喜欢截图各种APP页面发一些比较敏感的内容出来,于是就写了这篇文章

开头

从今年看到这个新闻开始,我就开始警觉了。

先回到技术

前端有一种东西叫水印,特别当你浏览一些内部系统的时候,大部分都会有,例如现在的企业微信,担心你截图发出去内部的重要信息。

小伙伴们会发现,水印大部分都是我们使用者可以看见的,例如企业微信的,这种我们叫明水印

可是还有一种,叫暗水印

什么叫暗水印?

就是你肉眼一眼看不到的水印,不影响你的浏览页面内容,无感知的把水印加进去。

这样一些敏感的内容,一旦泄露出去,就能通过网上的图片,解码找出来是谁的身份泄漏出去,而且往往一般的泄漏者不知道原来会有这个东西

所以有人会出现,截个图发给朋友,然后网上疯传,最后被定位到是他发的图片。这就是暗水印的一种使用

所以大家不要乱截图APP和各种页面,特别是比较敏感的内容

最简单的明水印实现

使用canvas生成,然后使用backgroud-repea至需要展示水印的区域~

 function __canvasWM({
    container = document.body,
    width = '250px',
    height = '200px',
    textAlign = 'center',
    textBaseline = 'middle',
    font = '15px microsoft yahei',
    fillStyle = 'rgba(184, 184, 184, 0.8)',
    content = '请勿外传',
    rotate = '30',
}) {
    const canvas = document.createElement('canvas');

    canvas.setAttribute('width', width);
    canvas.setAttribute('height', height);
    const ctx = canvas.getContext('2d');
    ctx.textAlign = textAlign;
    ctx.textBaseline = textBaseline;
    ctx.font = font;
    ctx.fillStyle = fillStyle;
    ctx.rotate((Math.PI / 180) * rotate);
    ctx.fillText(content, parseFloat(width) / 2, parseFloat(height) / 2);
    const base = canvas.toDataURL();
    const watermarkDiv = document.createElement('div');
    watermarkDiv.setAttribute(
        'style',
        `
          position:fixed;
          top:0;
          left:0;
          width:100%;
          height:100%;
          z-index:${9999999999};
          pointer-events:none;
          background-repeat:repeat;
          background-image:url('${base}');
          color:grey;
          opacity: 0.5`
    );

    container.style.position = 'relative';
    container.insertBefore(watermarkDiv, container.firstChild);
}

明水印的缺点

容易被找到对应的dom元素然后delete,我们有两种方式防止被删除:

1.setInterval去不断检测水印,如果不在了就继续生成

2.使用MutationObserver监测dom的变化,如果水印的dom节点变化了,就要继续生成

但是前端安全是一个比较麻烦的事,还是可以在控制台禁用javascript来做到去除的目的。

明水印肯定还有其他实现和防止去除的手段,安全是一个很深的知识点,这里点到为止

暗水印实现

同样,暗水印的实现,是多种的。我看过网上就有很多种,这里简单举两个例子

例如:https://juejin.cn/post/7023712210899697671这篇文章里面提到的

即在页面最顶部加上透明蒙层,蒙层携带文字信息,文字颜色也为透明,截图后文字信息肉眼不可见,通过ps等图片处理工具处理截图,才会将文字信息展示出来

通过PS设置,将看不见的水印内容展示出来

还有一种是业内通用的方案:

图片是由多个像素点组成的,而每个像素点轻微的变化,肉眼是无法辨别的

网上挺多这种文章的,我就从https://juejin.cn/post/7064201037321601032搞点代码过来了。时间原因,不自己写了

代码:

function createBackgroundImage(content, proportion, tiltAngle) {
  const can = document.createElement("canvas");
  can.width = document.body.clientWidth / proportion;
  can.height = document.body.clientHeight / proportion;
  const context = can.getContext("2d");
  context.rotate((-25 * Math.PI) / 180);
  context.font = "800 30px Microsoft JhengHei";
  context.fillStyle = "#000";
  context.textAlign = "center";
  context.textBaseline = "Middle";
  context.fillText(content, 100, 100);
  console.log(context.getImageData(0, 0, can.width, can.height));
  return can.toDataURL("image/png");
}

   const div = document.getElementById("root");
    div.style.backgroundImage = `url(${createBackgroundImage(
      "前端巅峰",
      6,
      10
    )})`;

效果:

其实这个效果背后是,root节点给了一个背景图:

那么我们获取下这个背景图的信息看看

console.log((createBackgroundImage("前端巅峰", 6, 10)));

对于 ImageData 对象中的每个像素,都存在着四方面的信息,即 RGBA 值:

  • R - 红色 (0-255)
  • G - 绿色 (0-255)
  • B - 蓝色 (0-255)
  • A - alpha 通道 (0-255; 0 是透明的,255 是完全可见的)
red=imgData.data[0];
green=imgData.data[1];
blue=imgData.data[2];
alpha=imgData.data[3];

Uint8ClampedArray则是对应的像素点,每四个表征一个像素点,然后从左往右,从上往下的顺序进行排列

我们只需要把水印内容塞进图片中即可


function getImageData(image) {
  const img = new Image();
  img.src = image;
  const myCanvas = document.createElement("canvas");
  myCanvas.width = img.width;
  myCanvas.height = img.height;
  const myContext = myCanvas.getContext("2d");
  myContext.drawImage(img, 0, 0);
  return myContext.getImageData(0, 0, myCanvas.width, myCanvas.height);
}

function mergeData(rawImageSrc, watermarkImageSrc) {
  return new Promise((resolve, reject) => {
    const img = new Image();
    img.onload = function () {
      const myCanvas = document.createElement("canvas");
      myCanvas.width = img.width;
      myCanvas.height = img.height;
      const ctx = myCanvas.getContext("2d");
      const bit = 0;
      const offset = 3;
      const oImageData = getImageData(rawImageSrc);
      const oData = oImageData.data;
      const newData = getImageData(watermarkImageSrc).data;
      for (let i = 0; i < oData.length; i++) {
        if (i % 4 === bit) {
          // 只修改目标通道
          if (newData[i + offset] === 0 && oData[i] % 2 === 1) {
            // 没有信息的像素,将目标通道的奇数像素改为偶数
            if (oData[i] === 255) {
              oData[i]--;
            } else {
              oData[i]++;
            }
          } else if (newData[i + offset] !== 0 && oData[i] % 2 === 0) {
            // 有信息的像素
            oData[i]++;
          }
        }
      }
      ctx.putImageData(oImageData, 0, 0);
      resolve(myCanvas.toDataURL("image/png"));
    };
    img.src = rawImageSrc;
  });
}

然后把水印内容从图片抽取出来:

function decrypt(watermarkImage) {
 return new Promise((resolve, reject) => {
        const img = new Image()
        img.onload = function () {

          const myCanvas = document.createElement("canvas");
          myCanvas.width = img.width;
          myCanvas.height = img.height;
          const ctx = myCanvas.getContext("2d")


          const imageData = getImageData(watermarkImage)
          var data = imageData.data;
          for (var i = 0; i < data.length; i++) {
            if (i % 4 == 0) {
              // 红色分量
              if (data[i] % 2 == 0) {
                data[i] = 0;
              } else {
                data[i] = 255;
              }
            } else if (i % 4 == 3) {
              // alpha通道不做处理
              continue;
            } else {
              // 关闭其他分量,不关闭也不影响答案,甚至更美观 o(^▽^)o
              data[i] = 0;
            }
          }

          ctx.putImageData(imageData, 0, 0)
          resolve(myCanvas.toDataURL("image/png"))
        }

        img.src = watermarkImage
      })
}

最终使用:

    const image1 = createBackgroundImage('前端巅峰', 3, 10)
    const image2 = createBackgroundImage('Peter666', 3, 10)
    mergeData(image1, image2).then(res => {
      console.log('res', res)
      decrypt(image2).then(res => {
        console.log('finalImage', res)
      })
    })

多说无益

我使用webContainer技术的给大家生成了一个demo

项目源代码链接:https://stackblitz.com/edit/react-a9ehdm?file=src/App.js

预览链接(打开控制台可以看到效果):https://react-a9ehdm.stackblitz.io

stackblitz上面可能会有报错, 大家可以把代码搞到本地跑起来

总结

所以大家没事不要乱截图,如果是敏感内容,暗水印实现方式很多种方式,总有一种你不知道的,会找到你。

本文由哈喽比特于2年以前收录,如有侵权请联系我们。
文章来源:https://mp.weixin.qq.com/s/4mDEU6obZG_fBm8V7s0H6A

 相关推荐

刘强东夫妇:“移民美国”传言被驳斥

京东创始人刘强东和其妻子章泽天最近成为了互联网舆论关注的焦点。有关他们“移民美国”和在美国购买豪宅的传言在互联网上广泛传播。然而,京东官方通过微博发言人发布的消息澄清了这些传言,称这些言论纯属虚假信息和蓄意捏造。

发布于:1年以前  |  808次阅读  |  详细内容 »

博主曝三大运营商,将集体采购百万台华为Mate60系列

日前,据博主“@超能数码君老周”爆料,国内三大运营商中国移动、中国电信和中国联通预计将集体采购百万台规模的华为Mate60系列手机。

发布于:1年以前  |  770次阅读  |  详细内容 »

ASML CEO警告:出口管制不是可行做法,不要“逼迫中国大陆创新”

据报道,荷兰半导体设备公司ASML正看到美国对华遏制政策的负面影响。阿斯麦(ASML)CEO彼得·温宁克在一档电视节目中分享了他对中国大陆问题以及该公司面临的出口管制和保护主义的看法。彼得曾在多个场合表达了他对出口管制以及中荷经济关系的担忧。

发布于:1年以前  |  756次阅读  |  详细内容 »

抖音中长视频App青桃更名抖音精选,字节再发力对抗B站

今年早些时候,抖音悄然上线了一款名为“青桃”的 App,Slogan 为“看见你的热爱”,根据应用介绍可知,“青桃”是一个属于年轻人的兴趣知识视频平台,由抖音官方出品的中长视频关联版本,整体风格有些类似B站。

发布于:1年以前  |  648次阅读  |  详细内容 »

威马CDO:中国每百户家庭仅17户有车

日前,威马汽车首席数据官梅松林转发了一份“世界各国地区拥车率排行榜”,同时,他发文表示:中国汽车普及率低于非洲国家尼日利亚,每百户家庭仅17户有车。意大利世界排名第一,每十户中九户有车。

发布于:1年以前  |  589次阅读  |  详细内容 »

研究发现维生素 C 等抗氧化剂会刺激癌症生长和转移

近日,一项新的研究发现,维生素 C 和 E 等抗氧化剂会激活一种机制,刺激癌症肿瘤中新血管的生长,帮助它们生长和扩散。

发布于:1年以前  |  449次阅读  |  详细内容 »

苹果据称正引入3D打印技术,用以生产智能手表的钢质底盘

据媒体援引消息人士报道,苹果公司正在测试使用3D打印技术来生产其智能手表的钢质底盘。消息传出后,3D系统一度大涨超10%,不过截至周三收盘,该股涨幅回落至2%以内。

发布于:1年以前  |  446次阅读  |  详细内容 »

千万级抖音网红秀才账号被封禁

9月2日,坐拥千万粉丝的网红主播“秀才”账号被封禁,在社交媒体平台上引发热议。平台相关负责人表示,“秀才”账号违反平台相关规定,已封禁。据知情人士透露,秀才近期被举报存在违法行为,这可能是他被封禁的部分原因。据悉,“秀才”年龄39岁,是安徽省亳州市蒙城县人,抖音网红,粉丝数量超1200万。他曾被称为“中老年...

发布于:1年以前  |  445次阅读  |  详细内容 »

亚马逊股东起诉公司和贝索斯,称其在购买卫星发射服务时忽视了 SpaceX

9月3日消息,亚马逊的一些股东,包括持有该公司股票的一家养老基金,日前对亚马逊、其创始人贝索斯和其董事会提起诉讼,指控他们在为 Project Kuiper 卫星星座项目购买发射服务时“违反了信义义务”。

发布于:1年以前  |  444次阅读  |  详细内容 »

苹果上线AppsbyApple网站,以推广自家应用程序

据消息,为推广自家应用,苹果现推出了一个名为“Apps by Apple”的网站,展示了苹果为旗下产品(如 iPhone、iPad、Apple Watch、Mac 和 Apple TV)开发的各种应用程序。

发布于:1年以前  |  442次阅读  |  详细内容 »

特斯拉美国降价引发投资者不满:“这是短期麻醉剂”

特斯拉本周在美国大幅下调Model S和X售价,引发了该公司一些最坚定支持者的不满。知名特斯拉多头、未来基金(Future Fund)管理合伙人加里·布莱克发帖称,降价是一种“短期麻醉剂”,会让潜在客户等待进一步降价。

发布于:1年以前  |  441次阅读  |  详细内容 »

光刻机巨头阿斯麦:拿到许可,继续对华出口

据外媒9月2日报道,荷兰半导体设备制造商阿斯麦称,尽管荷兰政府颁布的半导体设备出口管制新规9月正式生效,但该公司已获得在2023年底以前向中国运送受限制芯片制造机器的许可。

发布于:1年以前  |  437次阅读  |  详细内容 »

马斯克与库克首次隔空合作:为苹果提供卫星服务

近日,根据美国证券交易委员会的文件显示,苹果卫星服务提供商 Globalstar 近期向马斯克旗下的 SpaceX 支付 6400 万美元(约 4.65 亿元人民币)。用于在 2023-2025 年期间,发射卫星,进一步扩展苹果 iPhone 系列的 SOS 卫星服务。

发布于:1年以前  |  430次阅读  |  详细内容 »

𝕏(推特)调整隐私政策,可拿用户发布的信息训练 AI 模型

据报道,马斯克旗下社交平台𝕏(推特)日前调整了隐私政策,允许 𝕏 使用用户发布的信息来训练其人工智能(AI)模型。新的隐私政策将于 9 月 29 日生效。新政策规定,𝕏可能会使用所收集到的平台信息和公开可用的信息,来帮助训练 𝕏 的机器学习或人工智能模型。

发布于:1年以前  |  428次阅读  |  详细内容 »

荣耀CEO谈华为手机回归:替老同事们高兴,对行业也是好事

9月2日,荣耀CEO赵明在采访中谈及华为手机回归时表示,替老同事们高兴,觉得手机行业,由于华为的回归,让竞争充满了更多的可能性和更多的魅力,对行业来说也是件好事。

发布于:1年以前  |  423次阅读  |  详细内容 »

AI操控无人机能力超越人类冠军

《自然》30日发表的一篇论文报道了一个名为Swift的人工智能(AI)系统,该系统驾驶无人机的能力可在真实世界中一对一冠军赛里战胜人类对手。

发布于:1年以前  |  423次阅读  |  详细内容 »

AI生成的蘑菇科普书存在可致命错误

近日,非营利组织纽约真菌学会(NYMS)发出警告,表示亚马逊为代表的电商平台上,充斥着各种AI生成的蘑菇觅食科普书籍,其中存在诸多错误。

发布于:1年以前  |  420次阅读  |  详细内容 »

社交媒体平台𝕏计划收集用户生物识别数据与工作教育经历

社交媒体平台𝕏(原推特)新隐私政策提到:“在您同意的情况下,我们可能出于安全、安保和身份识别目的收集和使用您的生物识别信息。”

发布于:1年以前  |  411次阅读  |  详细内容 »

国产扫地机器人热销欧洲,国产割草机器人抢占欧洲草坪

2023年德国柏林消费电子展上,各大企业都带来了最新的理念和产品,而高端化、本土化的中国产品正在不断吸引欧洲等国际市场的目光。

发布于:1年以前  |  406次阅读  |  详细内容 »

罗永浩吐槽iPhone15和14不会有区别,除了序列号变了

罗永浩日前在直播中吐槽苹果即将推出的 iPhone 新品,具体内容为:“以我对我‘子公司’的了解,我认为 iPhone 15 跟 iPhone 14 不会有什么区别的,除了序(列)号变了,这个‘不要脸’的东西,这个‘臭厨子’。

发布于:1年以前  |  398次阅读  |  详细内容 »
 相关文章
Android插件化方案 5年以前  |  237270次阅读
vscode超好用的代码书签插件Bookmarks 2年以前  |  8108次阅读
 目录