javascript技巧

关注公众号 jb51net

关闭
首页 > 网络编程 > JavaScript > javascript技巧 > Web Component防篡改水印

使用Web Component实现防篡改水印

作者:程序员Alvin

Web Component内部有钩子天然支持被篡改时被触发,用来防篡改非常方便,所以本文就将使用Web Component实现防篡改水印,感兴趣的小伙伴可以了解下

这篇文章的关键可以分为3个部分,Web Component + 防篡改 + 水印生成。在使用Web Component之前,我已经通过MutationObserver实现了防篡改水印的第一版。但在了解到Web Component的特性之后,我认为也许用Web Component也不错,因为Web Component内部有钩子天然支持被篡改时被触发,用来防篡改非常方便。下面也会对MutationObserver与Web Component的实现做比较。

设计目标

设计一个hook用于插入水印至ref指定的组件中,被插入的水印节点应当不可篡改。

const { data: username } = useRequest(...)
const ref = useWatermark(username); // 水印组件会插入ref.current对应的DOM节点

return <div ref={ref}>
    {children}
</div>

水印生成原理

创建一个div节点,将背景设置为一个透明的水印图片,将z-index设置为10000叠加在站点上即可实现水印效果。

生成水印图

水印图可以在前端直接生成,可以使用canvas通过命令绘制,或预声明svg字符串。我选用的是svg字符串生成,因为使用svg清晰度较高,也比较简单。将svgString定义好,再转换成base64即可

        const svgString = `<svg xmlns="http://www.w3.org/2000/svg" width="400px" height="146px">
        <text x="10px" y="73px"
            text-anchor="start"
            transform="rotate(-20 0 73)"
            fill="rgba(40, 47, 56, 0.03)"
            font-weight="500"
            font-size="14"
            font-family="Helvetica Neue,Helvetica,Arial,PingFang SC,Hiragino Sans GB,Microsoft YaHei,WenQuanYi Micro Hei,sans-serif"
        >
            ${content}
        </text>
        <text x="210px" y="146px"
            text-anchor="start"
            transform="rotate(-20 200 146)"
            fill="rgba(40, 47, 56, 0.03)"
            font-weight="500"
            font-size="14"
            font-family="Helvetica Neue,Helvetica,Arial,PingFang SC,Hiragino Sans GB,Microsoft YaHei,WenQuanYi Micro Hei,sans-serif"
        >
            ${content}
        </text>
    </svg>`;
        const background = 'data:image/svg+xml;base64,' + window.btoa(svgString);

image

CSS与DIV布局

注意所有CSS都应该直接定义在div节点上,并且加上!important,这样能有效避免样式被覆盖。

position: absolute !important; 
top: 0px !important; 
right: 0px !important; 
bottom: 0px !important; 
left: 0px !important; 
overflow: hidden !important; 
display: block !important; 
opacity: 1 !important; 
z-index: 10000 !important; 
pointer-events: none !important; // 可以防止鼠标事件被水印节点拦截
background: url(${background});
const node = document.createElement('div');
watermarkRef.current = node;
node.setAttribute(
    'style',
    `position: absolute !important; top: 0px !important; right: 0px !important; bottom: 0px !important; left: 0px !important; overflow: hidden !important; display: block !important; opacity: 1 !important; z-index: 10000 !important; pointer-events: none !important; background: url(${background});`
);

防篡改原理

MutationObserve

const observer = new MutationObserver(function (entries) {
    // 因为MutationObserve没办法监听自己的属性是否被修改,自己是否被移除,只能监听父组件
    // 通过对父组件观测,entry.type = 'attributes'可以判断水印节点的属性是否被修改
    // entry.type = 'childList' 可以判断水印节点是否被移除
    for (const entry of entries) {
        if (
            (entry.type === 'attributes' && entry.target === watermarkRef.current) ||
            (entry.type === 'childList' && Array.from(entry.removedNodes).includes(watermarkRef.current))
        ) {
            removeWatermark();
            generateWaterMark();
            return;
        }
    }
});

const config = { attributes: true, childList: true, subtree: true };
observer.observe(
    parentNode, // 水印挂载到的父组件
    config
);

Web Component

使用Web Component的好处就是可以直接绑定回调函数,检测自己是否被篡改或移除。

class WatermarkElement extends HTMLElement {
  static observedAttributes = ["style"]; // 需要观测的属性

  constructor() {
    super();
  }

  connectedCallback() {
    // 当组件挂载至dom中,可以用来初始化
  }

  disconnectedCallback() {
    // 当组件从document中移除,用于检测水印被删除
  }

  adoptedCallback() {
    // 当组件在document中被移动
    // 若触发则表示水印被移动,可能失效
  }

  attributeChangedCallback(name, oldValue, newValue) {
    // 若触发表示style属性被操作,可能是恶意篡改
  }
}

customElements.define("watermark-element", MyCustomElement);

到此这篇关于使用Web Component实现防篡改水印的文章就介绍到这了,更多相关Web Component防篡改水印内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文