Understanding the Challenge
Last year, a situation arose where a confidential dashboard screenshot was shared externally, leaking sensitive financial data. Identifying the source of the leak was impossible without a traceable mark. Watermarks offer a solution by attributing leaks, rather than preventing them.
Shortcomings of Basic Watermarks
A straightforward watermark might involve placing a <div> element over the page:
<div class="watermark">user@example.com</div>
However, this method is easily bypassed by anyone familiar with browser DevTools, as they can quickly remove or hide the element, rendering it ineffective against intentional leakers.
Goals for a Robust Solution
Aiming to create a resilient library, the goals included:
- Tiling user identifiers across the page.
- Ensuring the watermark reappears if removed from the DOM.
- Resisting CSS manipulations.
- Redirecting users who open DevTools to a restricted access page.
- Logging all attempts to interact with the watermark, providing an audit trail.
Developing the Solution
The result is 'watermark-shield,' an extension of 'watermark-js-plus,' which provides:
- Self-healing overlay: Automatically restores if removed.
- MutationObserver: Detects CSS changes aimed at hiding the watermark.
- DevTools detection: Activates a callback before redirecting users.
- Audit logging: Records all interaction attempts for accountability.
This library is lightweight, at about 6 KB gzipped, with an additional 6 KB for the DevTools guard.
Simple Implementation
Installation and setup are straightforward:
npm install watermark-shield
import { WatermarkShield } from 'watermark-shield';
new WatermarkShield({
content: user.id,
protect: { devtool: true },
}).create();
This provides a tiled watermark and DevTools detection with default settings.
Practical Application
A realistic setup involves more detailed configuration:
new WatermarkShield({
content: user.id,
fontSize: '1.5vw',
fontColor: { light: '#000', dark: '#fff' },
globalAlpha: 0.18,
protect: {
devtool: true,
devtoolUrl: 'https://yourapp.com/security/blocked',
onDevtoolOpen: (detectorType) => {
navigator.sendBeacon('/api/audit/devtool', new Blob(
[JSON.stringify({
detectorType,
url: location.href,
ts: Date.now(),
})],
{ type: 'application/json' },
));
},
},
}).create();
Key Points:
- Server-side identity resolution: The server determines user identity through secure session data, not client-side inputs.
- Audit log importance: Logs provide crucial evidence even if client defenses are bypassed.
- Development considerations: Keep DevTools protection off in development environments to facilitate debugging.
Framework Integration
Watermark-shield supports major frameworks:
- Angular:
import { WatermarkShieldService } from 'watermark-shield/angular';
this.shield.create({ content: user.id, protect: { devtool: true } });
- React:
import { useWatermarkShield } from 'watermark-shield/react';
useWatermarkShield({ content: user.id, protect: { devtool: true } });
- Vue 3:
import { useWatermarkShield } from 'watermark-shield/vue';
useWatermarkShield({ content: user.value.id, protect: { devtool: true } });
Each integration follows a simple lifecycle: create, update, destroy.
Conclusion
The objective of watermark-shield is not to stop screenshots but to ensure they can be traced back to the source. By implementing this library, companies can change the mindset from "I won't be caught" to "I will be identified."
Get Started
Install watermark-shield and explore its capabilities to secure your web applications.