网站页面水印效果的实现(下):页面水印防篡改

上一节 (网站页面水印效果的实现(上):页面水印的添加)和大家介绍了页面水印如何生成以及如何使用,这一节来介绍如何防止水印被篡改,其实重点就是水印被删除。毕竟辛辛苦苦搞出来的水印,是为了保护自己的知识产权,结果被人轻轻松松就给搞掉了,岂不是悲哀。

要防止被篡改,就需要先知道有哪些方法可以进行篡改。直接在页面操作不太可能,但是其实如果不加防范,可以非常轻松的就把水印干掉。可以从客户端浏览器的开发者工具中,通过浏览Elements信息,找到水印对应的div将其删除,就可以轻松的将水印删除。

知道了水印如何被攻击和篡改,也就大致有了应对的解决方案。只要在程序设计时,监听水印信息的变化,从而判断是否需要重新生成水印即可。那又如何才能知道水印信息是否发生变化哪?

上一节中,曾提到有四点需要注意的关键因素:

一、要使用js动态加载div元素,不能通过直接在页面添加div标签的方式创建

        现在大家明白是为什么了吧,如果直接在html创建div元素,一旦被删除,如何重新生成,反而相当麻烦,倒不如从一开始就把他搞成动态的,这就简单多了,一旦发现前端将水印签名遮罩层div给删除了,直接重新运行一遍被watchEffect包裹的代码逻辑即可恢复水印。

二、要使用watchEffect方法而不是onMounted处理页面元素逻辑

        因为onMounted只会运行一次,除非页面被销毁重构,否则无论页面信息如何变化,都不会再执行内部的代码逻辑,因此也就无法恢复水印信息;

三、要使用js动态加载css样式,不能通过class方式添加

因为前端去修改你的class后台是监控不到的,他可以通过修改class来破坏水印信息。

这就是为什么,在上一节中将这几点给大家重点标红提示出来,当时没有做过多解释,在这里揭晓答案。

接下来处理如何监听的问题,JS为我们提供了一个接口-MutationObserver,用于观察DOM树的变化,可以监视指定DOM元素的所有变化,包括元素本身及其各级子元素的属性、内容的变化,并在变化发生时执行相应的操作。在不需要轮询的情况下,实时监测DOM变化,以便做出相应的处理。

于是在onMounted创建MutationObserver对象,并设置回调函数和监听配置。

onMounted(() => {
  obs = new MutationObserver((res) => {
    // console.info(res);
    for (let r of res) {
      for (let dom of r.removedNodes) {
        // 删除水印遮罩层div元素,触发重新生成水印
        if (customDiv == dom) {
          flag.value++;
          return;
        }
      }
      // 修改水印遮罩层div属性,触发重新生成水印
      if(customDiv == r.target){
        flag.value++;
        return;
      }
    }
  })
  obs.observe(yaken.value, {
    childList: true,           //监听目标节点的子节点的增加或删除事件
    attributes: true,          //监听目标节点的属性变化
    subtree: true,             //监听目标节点的所有后代节点而不仅仅是直接子节点
    characterData: true        //监听目标节点内容的变化
  });
})

首先创建了一个MutationObserver对象,并设置了回调函数,一旦监听到了变化,就将触发回调函数里面的逻辑。回调函数返回的结果res其实就是一个消息记录的集合,通过遍历这个集合,找到对应操作触发的消息,在通过比对目标对象与触发监听消息的对象是否一致,来判断某个页面组件及其各层子组件的属性、内容等是否被操作过,从而决定要进行什么样的后处理。在这段代码中,主要监听了两个事件,一个是节点删除事件的消息,另一个是目标节点属性被修改事件消息。只要这两项信息被修改,就立即触发watchEffect内部逻辑,重构水印信息(网站页面水印效果的实现(上):页面水印的添加)。哪又如何触发这个逻辑哪?要在watchEffect中监听整个div的变化吗?当然不是,watchEffect只需要知道情况发生变化了即可,它并不需要了解变化的具体细节,所以只需要设置一个标志位参数flag就够了。只要情况发生变化,就改变标志位的值,watchEffect通过监听标志位参数变化触发内部逻辑。 watch相同的是,它可以监听数据的变化,并在数据变化时自动执行传入的回调函数watch不同的是不需要指定要监听的具体数据,它会自动追踪回调函数中所使用的响应式数据,并在数据发生变化时触发回调。所以标志位参数flag一定要设置成响应式的,然后可以直接放到回到函数中。

创建了MutationObserver对象并设置好了回调函数就完事了吗?当然没有,上面乱七八糟的一大堆,都是对监听的后处理操作,你到底要监听谁、监听那些方面的信息你还没有配置,所以还需要给MutationObserver对象配置要监听的目标对象是谁,并且告诉它你要监听那些方面的变化。这里监听的对象是yaken引用的父元素的div,而不是我们动态创建的div,因为如果你监控了动态创建的div,一旦前端把它删除了,监控对象就消失了,监控机制也就失效了。这样一来,还得反复给重建构建的div元素配置监听,这样做显然不太明智。因此直接监控其父元素的变化。至于要监控哪些方面的变化,这里配置了四个属性:节点增删事件、节点属性变化、节点内容变化、各级子节点变化。

监听配置好了,再来修改一下watchEffect的代码逻辑:

let flag = ref(0);

watchEffect(() => {
      flag.value;
      if (!yaken.value) {
        return;
      } else {
        const {base64, adaptiveSize} = customWaterMark.value;
        // 判断元素是否为空,若不为空先移除元素
        if (customDiv) {
          customDiv.remove()
        }
        customDiv = document.createElement('div');

        customDiv.style.backgroundImage = `url(${base64})`;
        customDiv.style.backgroundSize = `${adaptiveSize}px ${adaptiveSize}px`;
        customDiv.style.backgroundRepeat = 'repeat';
        // customDiv.style.width = '100%';
        // customDiv.style.height = '100%';
        customDiv.style.zIndex = '999';
        // 设置绝对定位,以便图片能够填充整个区域
        customDiv.style.position = 'absolute';
        // 子元素相对于父元素的内边距,设置为0代表子元素完全覆盖父元素
        customDiv.style.inset = '0';
        // 必须设置此属性,否则水印遮罩层会阻止下层页面的操作事件
        customDiv.style.pointerEvents = 'none';

        yaken.value.append(customDiv);
      }
    })

和上一节 (网站页面水印效果的实现(上):页面水印的添加)代码比较一下,只是多了一个监听对象flag,以及添加了一个判断,用来判断customDiv对象是否为空,不为空,说明存在页面元素,那就先移除它再重新构建一个div即可。

最后不要忘记,在组件卸载的时候要取消监听,并且要将创建的水印区域div对象置空,以免存在内存泄漏的风险。

onUnmounted(() => {
  obs.disconnect();
  customDiv = null;
})

到此为止,一个简单的水印防篡改的代码就完成了。当然,除了页面元素的删除、属性内容的修改触发了水印信息重构外,还可以根据实际情况自定义更多的触发条件,以保证水印安全,这里就不做过多介绍了,大家在实际工作中用到了再自行添加即可。接下来可以做个测试,此时再打开浏览器控制台,删除水印div试试看,你会发现根本删不掉。其实不是没删掉,是删掉了,只不过瞬间又重新生成了一个新的而已。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值