前端實現(xiàn)網(wǎng)頁水印及防移除的多種方案
一、前言
在Web開發(fā)中,保護內容版權和防止信息泄露變得越來越重要。為網(wǎng)頁添加水印是一種常見的內容保護手段,可以用于標識內容來源、追蹤泄露渠道或聲明版權。本文將詳細介紹前端實現(xiàn)網(wǎng)頁水印的多種方法,并探討如何防止水印被輕易移除的技術方案。
二、網(wǎng)頁水印的基本實現(xiàn)原理
網(wǎng)頁水印的基本原理是在頁面內容之上疊加一層半透明的文字或圖片,使其不影響用戶正常瀏覽,但又能清晰可見。實現(xiàn)方式主要包括:
- Canvas繪制水印
- CSS背景圖水印
- SVG水印
- DOM元素覆蓋水印
三、基礎水印實現(xiàn)方案
3.1 Canvas繪制水印
Canvas是HTML5提供的繪圖API,非常適合用于生成動態(tài)水印。
function createWatermark(text) {
const canvas = document.createElement('canvas');
canvas.width = 300;
canvas.height = 200;
const ctx = canvas.getContext('2d');
ctx.font = '16px Arial';
ctx.fillStyle = 'rgba(200, 200, 200, 0.3)';
ctx.rotate(-20 * Math.PI / 180);
ctx.fillText(text, 50, 100);
return canvas.toDataURL('image/png');
}
function applyWatermark() {
const watermarkUrl = createWatermark('機密文檔 嚴禁外傳');
const watermarkDiv = document.createElement('div');
watermarkDiv.style.position = 'fixed';
watermarkDiv.style.top = '0';
watermarkDiv.style.left = '0';
watermarkDiv.style.width = '100%';
watermarkDiv.style.height = '100%';
watermarkDiv.style.pointerEvents = 'none';
watermarkDiv.style.backgroundImage = `url(${watermarkUrl})`;
watermarkDiv.style.zIndex = '9999';
document.body.appendChild(watermarkDiv);
}
window.onload = applyWatermark;
3.2 CSS背景圖水印
使用CSS的background-image屬性可以輕松實現(xiàn)全屏水印效果。
body {
position: relative;
}
body::after {
content: "";
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 9999;
pointer-events: none;
background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="300" height="200"><text x="50" y="100" font-family="Arial" font-size="16" fill="rgba(200,200,200,0.3)" transform="rotate(-20)">機密文檔 嚴禁外傳</text></svg>');
background-repeat: repeat;
}
3.3 SVG水印
SVG水印具有矢量特性,縮放不失真。
function createSvgWatermark(text) {
const svg = `
<svg xmlns="http://www.w3.org/2000/svg" width="300" height="200">
<text x="50" y="100" font-family="Arial" font-size="16"
fill="rgba(200,200,200,0.3)" transform="rotate(-20)">
${text}
</text>
</svg>`;
return `data:image/svg+xml;utf8,${encodeURIComponent(svg)}`;
}
function applySvgWatermark() {
const watermarkUrl = createSvgWatermark('機密文檔 嚴禁外傳');
const style = document.createElement('style');
style.innerHTML = `
body::after {
content: "";
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 9999;
pointer-events: none;
background-image: url("${watermarkUrl}");
background-repeat: repeat;
}
`;
document.head.appendChild(style);
}
3.4 DOM元素覆蓋水印
使用大量小DOM元素平鋪形成水印,增加移除難度。
function createDomWatermark(text) {
const container = document.createElement('div');
container.style.position = 'fixed';
container.style.top = '0';
container.style.left = '0';
container.style.width = '100%';
container.style.height = '100%';
container.style.zIndex = '9999';
container.style.pointerEvents = 'none';
container.style.overflow = 'hidden';
for (let i = 0; i < 200; i++) {
const watermark = document.createElement('div');
watermark.textContent = text;
watermark.style.position = 'absolute';
watermark.style.color = 'rgba(200, 200, 200, 0.3)';
watermark.style.fontSize = '16px';
watermark.style.transform = 'rotate(-20deg)';
watermark.style.userSelect = 'none';
const x = Math.random() * window.innerWidth;
const y = Math.random() * window.innerHeight;
watermark.style.left = `${x}px`;
watermark.style.top = `${y}px`;
container.appendChild(watermark);
}
document.body.appendChild(container);
}
四、水印防移除技術
基礎水印容易被開發(fā)者工具移除,我們需要增加防護措施。
4.1 防刪除機制
function protectWatermark() {
const watermark = document.getElementById('watermark');
// 監(jiān)控DOM變化
const observer = new MutationObserver((mutations) => {
mutations.forEach((mutation) => {
mutation.removedNodes.forEach((node) => {
if (node === watermark) {
document.body.appendChild(watermark);
}
});
});
});
observer.observe(document.body, {
childList: true,
subtree: true
});
// 定期檢查水印是否存在
setInterval(() => {
if (!document.contains(watermark)) {
document.body.appendChild(watermark);
}
}, 1000);
// 防止控制臺修改樣式
Object.defineProperty(watermark.style, 'display', {
set: function() {},
get: function() { return 'block'; }
});
}
4.2 防隱藏機制
function preventHideWatermark() {
const watermark = document.getElementById('watermark');
// 監(jiān)控樣式變化
const styleObserver = new MutationObserver(() => {
if (watermark.style.display === 'none' ||
watermark.style.visibility === 'hidden' ||
watermark.style.opacity === '0') {
watermark.style.display = 'block';
watermark.style.visibility = 'visible';
watermark.style.opacity = '1';
}
});
styleObserver.observe(watermark, {
attributes: true,
attributeFilter: ['style']
});
// 防止透明度被修改
Object.defineProperty(watermark.style, 'opacity', {
set: function(value) {
if (parseFloat(value) < 0.1) {
this._opacity = '0.3';
} else {
this._opacity = value;
}
},
get: function() {
return this._opacity || '0.3';
}
});
}
4.3 動態(tài)水印技術
function dynamicWatermark(userInfo) {
const canvas = document.createElement('canvas');
canvas.width = 300;
canvas.height = 200;
const ctx = canvas.getContext('2d');
// 繪制基礎水印
ctx.font = '16px Arial';
ctx.fillStyle = 'rgba(200, 200, 200, 0.3)';
ctx.rotate(-20 * Math.PI / 180);
ctx.fillText('機密文檔 嚴禁外傳', 50, 100);
// 添加用戶特定信息
ctx.font = '12px Arial';
ctx.fillText(`用戶: ${userInfo.name}`, 50, 130);
ctx.fillText(`時間: ${new Date().toLocaleString()}`, 50, 150);
// 應用水印
const watermarkDiv = document.createElement('div');
watermarkDiv.id = 'watermark';
watermarkDiv.style.position = 'fixed';
watermarkDiv.style.top = '0';
watermarkDiv.style.left = '0';
watermarkDiv.style.width = '100%';
watermarkDiv.style.height = '100%';
watermarkDiv.style.pointerEvents = 'none';
watermarkDiv.style.backgroundImage = `url(${canvas.toDataURL('image/png')})`;
watermarkDiv.style.zIndex = '9999';
document.body.appendChild(watermarkDiv);
// 定期更新水印
setInterval(() => {
dynamicWatermark(userInfo);
}, 60000); // 每分鐘更新一次
}
4.4 服務端配合的水印方案
前端水印容易被繞過,結合服務端可以增強安全性。
// 前端代碼
async function getWatermarkImage(userId) {
const response = await fetch(`/api/watermark?userId=${userId}`);
const blob = await response.blob();
return URL.createObjectURL(blob);
}
async function applyServerWatermark() {
const userId = getCurrentUserId(); // 獲取當前用戶ID
const watermarkUrl = await getWatermarkImage(userId);
const watermarkDiv = document.createElement('div');
watermarkDiv.style.position = 'fixed';
watermarkDiv.style.top = '0';
watermarkDiv.style.left = '0';
watermarkDiv.style.width = '100%';
watermarkDiv.style.height = '100%';
watermarkDiv.style.pointerEvents = 'none';
watermarkDiv.style.backgroundImage = `url(${watermarkUrl})`;
watermarkDiv.style.zIndex = '9999';
document.body.appendChild(watermarkDiv);
}
// 服務端示例(Node.js)
app.get('/api/watermark', (req, res) => {
const { userId } = req.query;
const canvas = createCanvas(300, 200);
const ctx = canvas.getContext('2d');
// 繪制水印
ctx.font = '16px Arial';
ctx.fillStyle = 'rgba(200, 200, 200, 0.3)';
ctx.rotate(-20 * Math.PI / 180);
ctx.fillText('機密文檔 嚴禁外傳', 50, 100);
ctx.fillText(`用戶ID: ${userId}`, 50, 130);
ctx.fillText(`時間: ${new Date().toISOString()}`, 50, 150);
// 返回圖片
const buffer = canvas.toBuffer('image/png');
res.set('Content-Type', 'image/png');
res.send(buffer);
});
五、高級防護方案
5.1 屏幕錄制防護
function preventScreenCapture() {
// 檢測常見錄屏軟件
const detectScreenCapture = () => {
const perf = window.performance || window.webkitPerformance;
const entries = perf?.getEntries() || [];
const screenCaptureApps = ['bandicam', 'obs', 'camtasia', 'screencast'];
for (const entry of entries) {
if (screenCaptureApps.some(app => entry.name.toLowerCase().includes(app))) {
document.body.innerHTML = '<h1>檢測到屏幕錄制軟件,內容保護已啟用</h1>';
return true;
}
}
return false;
};
// 檢測DevTools開啟
const detectDevTools = () => {
const devtools = /./;
devtools.toString = function() {
document.body.innerHTML = '<h1>開發(fā)者工具已禁用</h1>';
return '';
};
console.log('%c', devtools);
};
// 定期檢查
setInterval(() => {
detectScreenCapture();
detectDevTools();
}, 1000);
// 禁止右鍵菜單和快捷鍵
document.addEventListener('contextmenu', e => e.preventDefault());
document.addEventListener('keydown', e => {
if (e.ctrlKey && (e.key === 'u' || e.key === 's' || e.key === 'c')) {
e.preventDefault();
}
if (e.key === 'F12' || (e.ctrlKey && e.shiftKey && e.key === 'I')) {
e.preventDefault();
}
});
}
5.2 數(shù)字水印技術
數(shù)字水印將信息隱藏在視覺不可見的像素中。
function embedDigitalWatermark(imageElement, watermarkText) {
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
canvas.width = imageElement.width;
canvas.height = imageElement.height;
ctx.drawImage(imageElement, 0, 0);
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
const data = imageData.data;
// 將文本轉換為二進制
const binaryText = watermarkText.split('').map(char =>
char.charCodeAt(0).toString(2).padStart(8, '0')).join('');
// 在每個像素的最低有效位嵌入1位信息
for (let i = 0; i < binaryText.length; i++) {
const pixelIndex = i * 4;
if (pixelIndex >= data.length) break;
// 修改藍色通道的最低有效位
data[pixelIndex + 2] = (data[pixelIndex + 2] & 0xFE) | parseInt(binaryText[i]);
}
ctx.putImageData(imageData, 0, 0);
imageElement.src = canvas.toDataURL('image/png');
}
// 提取數(shù)字水印
function extractDigitalWatermark(imageElement, length) {
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
canvas.width = imageElement.width;
canvas.height = imageElement.height;
ctx.drawImage(imageElement, 0, 0);
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
const data = imageData.data;
let binaryText = '';
for (let i = 0; i < length * 8; i++) {
const pixelIndex = i * 4;
if (pixelIndex >= data.length) break;
// 提取藍色通道的最低有效位
binaryText += (data[pixelIndex + 2] & 1).toString();
}
// 將二進制轉換為文本
let text = '';
for (let i = 0; i < binaryText.length; i += 8) {
const byte = binaryText.substr(i, 8);
text += String.fromCharCode(parseInt(byte, 2));
}
return text;
}
六、水印實現(xiàn)流程圖

七、最佳實踐建議
- 多層防護:結合多種水印技術,增加移除難度
- 用戶特定信息:在動態(tài)水印中包含用戶ID、時間等信息,便于追蹤
- 性能考慮:避免過于復雜的水印影響頁面性能
- 響應式設計:確保水印在不同屏幕尺寸下都能正常顯示
- 法律合規(guī):確保水印使用符合當?shù)胤煞ㄒ?guī)
八、總結
網(wǎng)頁水印的實現(xiàn)和防護是一個不斷演進的技術領域。本文介紹了從基礎到高級的多種水印實現(xiàn)方案,以及相應的防移除技術。需要注意的是,沒有任何前端水印方案是絕對安全的,但通過組合多種技術可以顯著提高移除難度。對于高安全性要求的場景,建議結合服務端驗證和數(shù)字水印等高級方案。
在實際應用中,應根據(jù)具體需求選擇合適的水印方案,平衡安全性、用戶體驗和性能開銷。隨著Web技術的不斷發(fā)展,水印技術也將持續(xù)演進,開發(fā)者需要保持對新技術的學習和關注。
以上就是前端實現(xiàn)網(wǎng)頁水印及防移除的多種方案的詳細內容,更多關于前端網(wǎng)頁水印及防移除的資料請關注腳本之家其它相關文章!
相關文章
javascript 同時在IE和FireFox獲取KeyCode的代碼
以前一直在IE8中測試網(wǎng)站,后來寫的一部分含有Ajax的代碼出現(xiàn)了故障,不得已下載了Firefox以及它的插件Firebug,才發(fā)現(xiàn),F(xiàn)F不支持windows.event事件。于是換了一種思路。2010-02-02
回車直接實現(xiàn)點擊某按鈕的效果即觸發(fā)單擊事件
這篇文章主要介紹了回車直接實現(xiàn)點擊某按鈕的效果即觸發(fā)單擊事件,需要的朋友可以參考下2014-02-02
javascrip高級前端開發(fā)常用的幾個API示例詳解
這篇文章主要為大家介紹了javascrip高級前端開發(fā)中常用的幾個API示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步2021-11-11

