前端 -水印的生成

一、水印的生成

明水印的生成方式主要可以归为两类,一种是 纯 html 元素(纯div),另一种则为背景图(canvas/svg)。

div实现
test = () => {
   function cssHelper(el, prototype) {
      for (const i in prototype) {
          el.style[i] = prototype[i];
      }
   }
  const waterWrapper = document.createElement('div');
  cssHelper(waterWrapper, {
      position: 'fixed',
      top: '0px',
      right: '0px ',
      bottom: '0px',
      left: '0px',
      overflow: 'hidden',
      display: 'flex',
      'flex-wrap': 'wrap',
      'pointer-events': 'none'
  });
  const waterHeight = 100;
  const waterWidth = 180;
  const { clientWidth, clientHeight } = document.documentElement || document.body;
  const column = Math.ceil(clientWidth / waterWidth);
  const rows = Math.ceil(clientHeight / waterHeight);

  function createItem() {
      const item = document.createElement('div');
      item.innerHTML = 'test';
      cssHelper(item, {
          position: 'absolute',
          top: '50px',
          left: '50px',
          fontSize: '16px',
          color: '#000',
          lineHeight: 1.5,
          opacity: 0.1,
          transform: 'rotate(-15deg)',
          transformOrigin: '0 0',
          userSelect: 'none',
          whiteSpace: 'nowrap',
          overflow: 'hidden'
      });
      return item;
  }
  for (let i = 0; i < column * rows; i += 1) {
      const wrap = document.createElement('div');
      cssHelper(wrap, Object.create({
          position: 'relative',
          width: `${waterWidth}px`,
          height: `${waterHeight}px`,
          flex: `0 0 ${waterWidth}px`,
          overflow: 'hidden'
      }));
      wrap.appendChild(createItem());
      waterWrapper.appendChild(wrap);
  }
  document.body.appendChild(waterWrapper);
  }
背景图实现
canvas
.watermark {
  position: fixed;
  top: 0px;
  right: 0px;
  bottom: 0px;
  left: 0px;
  pointer-events: none;
  background-repeat: repeat;
}

test = () => {
    function createWaterMark() {
      const angle = -20;
      const txt = 'test';
      const canvas = document.createElement('canvas');
      canvas.width = 180;
      canvas.height = 100;
      const ctx = canvas.getContext('2d');
      ctx.clearRect(0, 0, 180, 100);
      ctx.fillStyle = '#000';
      ctx.globalAlpha = 0.1;
      ctx.font = '16px serif';
      ctx.rotate(Math.PI / 180 * angle);
      ctx.fillText(txt, 0, 50);
      return canvas.toDataURL();
    }
    const watermakr = document.createElement('div');
    watermakr.className = 'watermark';
    watermakr.style.backgroundImage = `url(${createWaterMark()})`;
    document.body.appendChild(watermakr);
  }

svg
.watermark {
  position: fixed;
  top: 0px;
  right: 0px;
  bottom: 0px;
  left: 0px;
  pointer-events: none;
  background-repeat: repeat;
}

function createWaterMark() {
   const svgStr =
   `<svg xmlns="http://www.w3.org/2000/svg" width="180px" height="100px">
       <text x="0px" y="30px" dy="16px"
           text-anchor="start"
           stroke="#000"
           stroke-opacity="0.1"
           fill="none"
           transform="rotate(-20)"
           font-weight="100"
           font-size="16"
           >
           test
       </text>
   </svg>`;
   return `data:image/svg+xml;base64,${window.btoa(unescape(encodeURIComponent(svgStr)))}`;
 }
    const watermakr = document.createElement('div');
    watermakr.className = 'watermark';
    watermakr.style.backgroundImage = `url(${createWaterMark()})`
    document.body.appendChild(watermakr);
二、水印的防御

主要有三点

  • 水印元素本身是否被移除
  • 水印元素属性是否被篡改(display: none …)
  • 水印元素的子元素是否被移除和篡改 (element生成的方式 )
MutationObserver

js 有一个方法叫做 MutationObserver,能够监控元素的改动。

.watermark {
  position: fixed;
  top: 0px;
  right: 0px;
  bottom: 0px;
  left: 0px;
  pointer-events: none;
  background-repeat: repeat;
}
function createWaterMark() {
      const angle = -20;
      const txt = 'test';
      const canvas = document.createElement('canvas');
      canvas.width = 180;
      canvas.height = 100;
      const ctx = canvas.getContext('2d');
      ctx.clearRect(0, 0, 180, 100);
      ctx.fillStyle = '#000';
      ctx.globalAlpha = 0.1;
      ctx.font = '16px serif';
      ctx.rotate(Math.PI / 180 * angle);
      ctx.fillText(txt, 0, 50);
      return canvas.toDataURL();
  }
  const watermakr = document.createElement('div');
  watermakr.className = 'watermark';
  watermakr.style.backgroundImage = `url(${createWaterMark()})`;
  document.body.appendChild(watermakr);

  const targetNode = document.body;

  // 观察器的配置(需要观察什么变动)
  const config = { attributes: true, childList: true, subtree: true };
  // 当观察到变动时执行的回调函数
  // eslint-disable-next-line no-unused-vars
  // eslint-disable-next-line func-names
  const callback = function (mutationsList) {
      // Use traditional 'for loops' for IE 11
      for (const mutation of mutationsList) {
          mutation.removedNodes.forEach((item) => {
              if (item === watermakr) {
                  document.body.appendChild(watermakr);
              }
          });
      }
  };
  // 创建一个观察器实例并传入回调函数
  const observer = new MutationObserver(callback);
  // 以上述配置开始观察目标节点
  observer.observe(targetNode, config);
  }
三、水印的破解
  1. 打开了Chrome Devtools 找到对应的元素,直接按 delete 即可删除。
  2. 打开Chrome Devtools,点击设置 - Debugger - Disabled JavaScript 。
  3. 复制一个 body 元素,然后将原来 body 元素的删除。
  4. 打开一个代理工具,例如 charles,将生成水印相关的代码删除。

第一种方法只能用于没有任何防御的水印,如果用了防御手段,比如 MutationObserver那么就要用后三种方法

参考链接
谈谈前端水印

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值