大家好😁。
上個月,我們公司的內部敏感文件(PRD)截圖,竟然出現在了競品的群裡。
老闆大发雷霆,要求技術部徹查:到底是誰洩露出去的?😠
但問題是,文件是純文本的,截圖上也沒有任何顯示的水印(那種寫著員工名字的大黑字,太醜了,產品經理也不讓加)。
怎麼查?
這時,我默默地打開了我的VS Code,給老闆演示了一個技巧:
老闆,其實洩露的那段文字裡,藏著那個人的工號,只是你肉眼看不見。
今天,我就來揭秘這個技術——基於零寬字符(Zero Width Characters)的盲水印技術。學會這招,你也能給你的頁面加上隱形追蹤器。
在Unicode字符集中,有一類神奇的字符。它們存在,但不占用任何寬度,也不顯示任何像素。
簡單說,它們是隱形的。
最常見的幾個:
\u200b (Zero Width Space):零寬空格\u200c (Zero Width Non-Joiner):零寬非連字符\u200d (Zero Width Joiner):零寬連字符我們可以在Chrome控制台裡試一下:
console.log('A' + '\u200b' + 'B');
// 輸出: "AB"
// 看起來和普通的 "AB" 一模一樣
但是,如果我們檢查它的長度:
console.log(('A' + '\u200b' + 'B').length);
// 輸出: 3
看到沒?😁
原理非常簡單,就是利用這些隱形字符,把用戶的信息(比如工號User_9527),編碼進一段正常的文本裡。
步驟如下:
準備密碼本:我們選兩個零寬字符,代表二進制的 0 和 1。
\u200b 代表 0\u200c 代表 1\u200d 作為分割符。加密(編碼):
解密(解碼):
是不是很神奇?🤣
不廢話,直接上代碼。你可以直接複製到控制台運行。
加密函數 (Inject Watermark)
// 零寬字符字典
const zeroWidthMap = {
'0': '\u200b', // Zero Width Space
'1': '\u200c', // Zero Width Non-Joiner
};
function textToBinary(text) {
return text.split('').map(char =>
char.charCodeAt(0).toString(2).padStart(8, '0') // 轉成8位二進制
).join('');
}
function encodeWatermark(text, secret) {
const binary = textToBinary(secret);
const hiddenStr = binary.split('').map(b => zeroWidthMap[b]).join('');
// 將隱形字符,插入到文本的第一個字符後面
// 你也可以隨機分散插入,更難被發現
return text.slice(0, 1) + hiddenStr + text.slice(1);
}
// === 測試 ===
const originalText = "公司機密文件,嚴禁外傳!";
const userWorkId = "User_9527";
const watermarkText = encodeWatermark(originalText, userWorkId);
console.log("原文:", originalText);
console.log("帶水印:", watermarkText);
console.log("肉眼看得出區別嗎?", originalText === watermarkText); // false
console.log("長度對比:", originalText.length, watermarkText.length);
當你把 watermarkText 複製到微信、飛書或者任何地方,那串隱形字符都會跟著一起被複製過去。
解密函數的實現
現在,假設我們拿到了洩露出去的這段文字,怎麼還原出是誰幹的?
// 反向字典
const binaryMap = {
'\u200b': '0',
'\u200c': '1',
};
function decodeWatermark(text) {
// 1. 提取所有零寬字符
const hiddenChars = text.match(/[\u200b\u200c]/g);
if (!hiddenChars) return '未發現水印';
// 2. 轉回二進制字符串
const binaryStr = hiddenChars.map(c => binaryMap[c]).join('');
// 3. 二進制轉文本
let result = '';
for (let i = 0; i < binaryStr.length; i += 8) {
const byte = binaryStr.slice(i, i + 8);
result += String.fromCharCode(parseInt(byte, 2));
}
return result;
}
// === 測試抓內鬼 ===
const leakerId = decodeWatermark(watermarkText);
console.log("抓到內鬼工號:", leakerId); // 輸出: User_9527
微信或者飛書 複製出來的文案 👇
當然可以,但前提是你知道它的存在。
對於不懂技術的普通員工,他們複製粘貼文字時,根本不會意識到自己已經暴露了🤔
如果遇到了懂技術的內鬼,他可能會:
text.replace(/[\u200b-\u200f]/g, '') 就能清除。雖然它不是萬能的,但它是一種極低成本、極高隱蔽性的防禦手段。
技術本身就沒什麼善惡。
我分享這個技術,不是為了讓你去監控誰,而是希望大家多掌握一種防禦性編程的思路。
在Web開發中,除了明面上的UI和交互,還有很多像零寬字符這樣隱秘的角落,藏著一些技巧。
下次如果面試官問你:除了顯式的水印,你還有什麼辦法保護頁面內容?
你可以自信地拋出這個方案,絕對能震住全場😁。