跪拜 Guibai
← All articles
Frontend

Frontend Watermarks That Survive DevTools: From Canvas to Anti-Debugging

By 前端阿凡 ·
Read original on juejin.cn ↗ Google Translate ↗ Alt translation

Internal admin panels displaying revenue, PII, or strategy documents are screenshot targets. A watermark that disappears in DevTools provides no deterrence and no audit trail. These techniques raise the cost of removal from a single keystroke to a debugging session, buying time for server-side attribution to work.

Summary

A `position: fixed` div with low opacity takes two minutes to write and one second to delete in DevTools. The real problem is that the DOM is inherently inspectable and mutable. Moving the watermark out of the DOM tree — into a Canvas-rendered background image — removes the simplest attack vector, but a user who knows CSS can still override `background-image`.

Layering a MutationObserver on top watches for style attribute changes and restores the watermark immediately. A polling fallback catches cases where the observer itself is disconnected. For higher-stakes internal tools, rendering the watermark through a `::before` pseudo-element with `!important` on every property makes it inaccessible to direct DOM deletion and resistant to style injection.

None of this stops a determined user from screenshotting and cropping. The watermark's real job is post-incident traceability: every leaked image carries an employee ID, and server-side logs tie the request to a specific person regardless of what happened in the browser.

Takeaways
CSS-only watermarks are DOM nodes that can be deleted, hidden, or style-overridden in seconds.
Rendering the watermark onto a Canvas and applying it as a CSS background image removes it from the DOM tree entirely.
MutationObserver can watch for style changes and restore the watermark before a screenshot completes.
A polling interval catches cases where the observer itself is disconnected or killed via breakpoints.
Pseudo-elements with `!important` on every property resist both DOM deletion and casual style overrides.
Overriding `MutationObserver.prototype.disconnect` blocks attempts to disable the watcher, but degrades the development experience and should be restricted to sensitive internal systems.
Frontend watermarks are a deterrent and a traceability mechanism, not a confidentiality guarantee; server-side watermarking and request logging provide the actual attribution.
Conclusions

The escalation from CSS overlay to Canvas to MutationObserver mirrors a general security pattern: each defense raises the attacker's required skill level without ever reaching absolute protection.

Calling `toDataURL` on every restoration is wasteful; caching the data URL once is an obvious optimization that the examples omit for clarity but that production code must include.

The `::before` approach exploits a DevTools blind spot — pseudo-elements are harder to select and delete than regular DOM nodes, making it a cheap but effective hardening step.

The article's closing honesty about AI-powered watermark removal reframes the entire exercise: the goal is not to prevent leaks but to ensure every leak is attributable.

Concepts & terms
MutationObserver
A browser API that watches for changes to the DOM tree or element attributes and fires a callback. Used here to detect when a watermark's CSS is modified or removed and restore it immediately.
Canvas toDataURL
A method on the HTML Canvas element that serializes the current drawing into a base64-encoded data URL, which can be used directly as a CSS background-image value.
Pseudo-element (::before / ::after)
CSS-generated content that exists in the rendering tree but not as a real DOM node. DevTools cannot directly select and delete pseudo-elements the way they can with regular elements.
Source: juejin.cn ↗ Google Translate ↗ Backup ↗