Again, it’s a question of security.

Generally speaking, the watermark refers to the platform user name watermark in the corner of the image. As shown in the image below, the platform will embed a watermark in the image as soon as the image is uploaded to the platform. Of course, some platforms will also provide a switch to enable the watermark to be displayed, or to enable the watermark to be applied only when the image is saved.

Ming watermark

The realization of this watermark is actually relatively simple, that is, to combine two pictures into one, or to draw content directly on the original picture:

<img id="pic" src="https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/f3c3c98ebfce4ae28db981dfabedc1d8~tplv-k3u1fbpfcp-zoom-1.image" alt="Original picture" height="500" crossorigin="anonymous">
<div>Photo by Claudio Schwarz | @purzlbaum on Unsplash</div>
Copy the code
window.onload = () = > {
    const pic = document.querySelector('#pic');
    const canvasNode = document.createElement('canvas');
    const picWithWatermark = createImageWithWatermark(pic, canvasNode);
    pic.src = picWithWatermark;
}


/** * create image with watermark. *@param {HTMLImageElement} Img image node - image element. *@param {HTMLCanvasElement} Canvas Canvas node - Canvas Element. *@returns Base64-pic with watermark. */
const createImageWithWatermark = (img, canvas) = > {
    const imgWidth = img.width;
    const imgHeight = img.height;
    canvas.width = imgWidth;
    canvas.height = imgHeight;

    const ctx = canvas.getContext('2d');
    ctx.drawImage(img, 0.0, imgWidth, imgHeight);
    ctx.font = '16px YaHei';
    ctx.fillStyle = 'black';
    ctx.fillText('Photo by Claudio Schwarz | @purzlbaum on Unsplash'.20.20);

    return canvas.toDataURL('image/jpg');
}
Copy the code

This is the complete code, more detailed code can be viewed at github link.

Ordinary users say the watermark is above this kind, but for developers, the watermark contains more categories.

For example, we can see this watermark on some (possibly all) systems on the corporate Intranet.

Here, the watermark color is black just to see the effect more directly. In the real use of this watermark, white and transparent ones will be used.

The watermark is a bit like said before, synthesize two pictures a kind of way, but on the front page, we are using a transparent canvas container to cover the entire page, and then draw the “logo” on canvas, visit the current page is used to identify the user identity, as a result, whether your screenshots or pictures, As long as there’s a watermark on the image, we can use that watermark to track the person who leaked this information.

I know this watermark is a DOM node, so go to the console, find it, and delete it.

Bright watermark defense

That’s a good question, but it’s not a big question, and if you want to delete it, it’s totally fine.

I can’t control what you’re doing, but I can detect that you’re manipulating this DOM node, and I’m sorry, I don’t care how you’re manipulating this node, but for safety, I’m definitely going to redraw this watermark.

But I don’t think it’s enough just to repaint the watermark, it might make you fight with me, that’s no good, I have to teach you a lesson, still can’t let you get what you want, how to do? As soon as you manipulate my DOM, I’ll just leave the page blank and reload the page. This prevents the user from manipulating the DOM node.

To do this, we need to use the MutationObserver function provided by JS, which listens for changes to the container.

The code is as follows:

// The container listens for a callback
const cb = function (mutationList, observer) {
    for (const mutation of mutationList) {
        if (mutation.type === 'childList') {
            const { removedNodes = [] } = mutation;
            // If the watermark container changes, then clear the page and reload
            const node = Array.prototype.find.apply(removedNodes, [(node= > node.id === 'page-watermark')])
            if (node) {
                targetNode.innerHTML = ' ';
                window.location.reload(); }}}}// Target DOM node
const targetNode = document.querySelector('#watermark-body');
// Create a listener
const observer = new MutationObserver(cb);
observer.observe(targetNode, {
    attributes: true.childList: true
});
Copy the code

MutationObserver is part of the DOM3 Event specification to replace older Mutation Events and can be used with confidence.

Although the above is a global watermark, but you can only watermark part of the content, but the global watermark implementation cost is lower, the cost is small, for the Intranet system, sacrifice this user experience, is not a very serious problem, it is acceptable.

Maybe some people will say, I have opened the DOM, that I study the DOM structure, write a crawler to crawl data, or directly copy the content of the DOM inside not good, you this watermark still have what the meaning of existence?

Unable to refute, but should clear is that data this is illegal, want to be responsible for the legal responsibility, and you the crawler is sure to run on a computer, this would be no need for the watermark, we can check the IP directly, tracking to the corresponding people to go, and we add a watermark is just a convenient tracking tool.

Second, the front end and the crawler battle of intelligence, you crawl data from the web, then I try to find a way to not directly generate text, but some keywords to replace images, so that you crawl to the result, is a string of useless text.

Which brings us to the anti-reptilian thing. So far, we’ve been talking about open watermarks, which are certainly fine for internal networks, but what about external websites? It is not appropriate to add such a watermark, and it is not acceptable to sacrifice the user experience.

So we started thinking, can we add a watermark that we can’t see?

Dark watermark

Of course it’s ok, that’s what we’re going to talk about next.

As we know from the name, dark watermark and bright watermark are just opposite, we can not see this kind of watermark, and the difference between the principle and implementation of this kind of watermark and bright watermark is relatively large.

Let’s look at the principle.

I don’t know if you’ve heard of steganography 1. “Steganography is the art and science of information hiding, the act or content of a message from anyone other than the intended recipient.” In essence, it is still cryptography.

Append file contents

We can write information to an image in various ways. The most common one is to write steganography content in binary form into an image. Let’s take the following image as an example:

Save the image locally (original.png) and run the following command:

tail -c 50 1.png
Copy the code

You can see that the result is a string of garbled characters (using the Hex viewer you can see the binary stream of the file, in this case utF-8, garbled characters are normal), execute the command on the file:

cat original.png > result.png
echo testWrite >> result.png
tail -c 50 result.png
Copy the code

After we generate a new image, we append a string of characters to the end of the image. We can see that the image is still displayed normally.

In addition, it is not possible to add a string to the header of the file because the header contains information such as the file format. If you insert information into the header of a file, commercially available software cannot correctly identify the type of file.

Of course, you can design your own codecs to create new file types.

This is just one way, and the method is very violent, after processing the image file from the original file is a certain size change (but relatively small, can be measured in bytes). It would be smarter to write the encrypted information into the binary stream of the image in a way that only the encryptor can access it.

But even with complex encryption method, also is not enough, because this can ensure that people in the use of original image, we can identify the source of the image, the spread route, but if through the screenshots or pictures, we can’t get this data, because we did this time relative to the processing of pictures, he already is a new picture.

Modify the RGB component value

Let’s take another example, a small change in RGB component value: to cover an image with an invisible image, in simple terms, I can write the watermark information in a single channel of the image (such as CHANNEL B in RGB). In fact, it is still difficult to understand, for example:

Now to combine the left and right sides of the picture, but can not let the right picture content observed on the left picture, at this time what we need to do is to write the watermark picture in accordance with certain rules in the RGB channel of this picture.

Preprocessing, Sir Into the right watermark image encoding1.Get rGBA data for two images from canvas2.Put the b (blue) channel value of the left image -1, that is, b &0xfffffffe
3.Read the right channel B data, encountered greater than0, the value of b channel at the corresponding position on the left side +1, that is, a | b0x00000001decoding1.Get the RGBA data of the image2.B & is encountered while reading channel B data0x00000001 > 0, indicating that there is watermark information, set it to255, except channel A (alpha channel is not color channel), all data of other channels are set to0


// +1,-1 because the magnitude change is very small, does not affect the image display
Copy the code

In fact, the picture of blue words on black is the watermark data decoded, the detailed code:

Does this seem to preserve our watermark while users take screenshots? Not really.

This is the result of decoding the screenshots. Obviously, the pictures after QQ screenshots can not decode the watermark content we need, and even after the pictures are compressed, our watermark may be lost. Therefore, this is not a reliable way of watermarking.

So how can we make sure that our watermark works, at least for screenshots?

Is not no, first determine where our watermark to add (make sure) demand, because the photo is nothing more than web search results, or we have to figure most come from the web page, so we consider is covered a layer of the watermark on the web page, ensure that the user from the picture taken on web pages can be we trace to the source.

The general solution is to write CSS again, but with the background image at the top and the opacity set very low.

The code is very simple, in fact, it is enough to spread a background image all over the screen, and then set opacity to a level that cannot be observed by the naked eye.

window.onload = () = > {
    const width = document.body.clientWidth;
    const height = document.body.clientHeight;

    const maskDiv = document.createElement('div');
    maskDiv.id = 'mask_watermark';
    maskDiv.style.position = 'absolute';
    maskDiv.style.backgroundImage = 'url(./1.jpg)';
    maskDiv.style.backgroundRepeat = 'repeat';
    maskDiv.style.visibility = ' ';
    maskDiv.style.left = '0px';
    maskDiv.style.top = '0px';
    maskDiv.style.overflow = "hidden";
    maskDiv.style.zIndex = "9999";
    maskDiv.style.pointerEvents = "none";
    maskDiv.style.opacity = 0.005;
    maskDiv.style.fontSize = '20px';
    maskDiv.style.color = '# 000';
    maskDiv.style.textAlign = "center";
    maskDiv.style.width = `${width}px`;
    maskDiv.style.height = `${height}px`;
    maskDiv.style.display = "block";
    document.body.appendChild(maskDiv);
}
Copy the code

On the left is the following image from the web page, and on the right is the image 2 after processing in the PS tool, obviously you can see the watermark we set.

And there are many ways to generate pictures, can be front-end generation, can also be sent information to the back end, the back end generates a picture, and then the front end as a background picture.

If you want to get the result on the right side, you don’t need photoshop to do it, you can do it in other ways.

At this point, I’m done with the front end, but for those of you who don’t like it, my image is watermarked now, but what if I save the original image? We can do that with the RGB component.

What if I download the image and capture it on the original one? Indeed, there is very little that can be done on the front end at this point. We have not dealt with, but in the image dark watermarking, or blind watermarking this field, there are more effective ways to resist attack (to watermark), such as frequency domain, airspace transformation. This transformation is kind of a cliche, and I won’t explain it much.

Added two sentences

The concept of watermarking is generalized, and it does not mean that only information displayed in a corner of the picture can be called watermarking.

Append the information to the end of the file was chosen for a reason, not a blind choice. Any file contains an end-of-file character, just as the header specifies the format of the file. Even if you change the suffix, I can read the contents of the header to identify the actual format of the file.

In addition, we know that the file suffix name can be changed at will, if only through the file suffix name detection, then absolutely can be bypassed, and then any file upload security problems.

If changing layer blending mode fails, try changing the RGB curve of the image

Refer to the article


  1. Can’t say secret – front end can also play of image steganographic | AlloyTeam↩
  2. What algorithm does the invisible watermark of Alibaba Intranet use? – Mize’s answer – Zhihu↩