上周的時候,朋友圈的直升飛機不知道為什麼就火了,很多朋友開著各種花式飛機帶著起飛。
圖片來自網絡還沒來得及了解咋回事來著,這個直升飛機就🔥到了微博熱搜。
圖片來自網絡後面越來越多人開來他們的直升飛機,盤旋在朋友圈上方。於是很多朋友開來他們的坦克,專打直升飛機,一轟一個準。
圖片來自網絡程式設計師朋友應該都很熟悉 Unicode (萬國碼),它幾乎包含世界上所有符號,比如組成直升飛機這幾個特殊符號對應的 Unicode 碼分別為:
ps:推薦一個網站,可以根據符號搜對應的 Unicode 碼:https://unicode.yunser.com/unicode
除了這些正常字符以外,Unicode 還包含著各種各樣的奇葩字符。
奇葩字符除了我們熟知的這些正常的文字以外,Unicode 中還有一些奇怪的文字,比如下面這些文字:
這咋讀?某少?世代?恩?超出認知範圍除了這些奇怪文字以外,Unicode 還有一些奇葩的符號。
例如下面一整套的麻將牌:
三缺一?一整套的撲克牌:
對三?要不起!一整套的西洋棋:
不會玩--!除了這些,通過組合符合,我們還可以造出各種各樣的顏文字(๑•̀ㅂ•́)و✧、
另外 Unicode 還收錄著我們常用的 Emoji 。
除此之外,Unicode 中還有一些特殊字符的,利用這些字符,我們還可以玩出很多有趣的騷操作。
組合字符Unicode 有一類字符稱為組合字符,它可以附加在前一個非組合字符上,從而使整體看起來像是一個字符。
組合字符原來目的是為了解決一些地區語言、文字特殊的需要,比如說泰文聲調符號與母音符號。
正常使用的情況下,這些組合字符數量都會有一些限制。但是在 Unicode 組合字符設計上,並沒有加這種限制,這樣使我們可以無限加這類組合字符。
利用這個特性,可以達到一些惡搞效果,比如「擊穿天花板」與「鑿穿地板」的效果。
上面實現原理其實是利用以下兩個組合字符:
上翻字符下翻字符只要複製這兩個字符相應的 HTML 代碼,跟在正常的字符後面,就可以使這兩個字符附加在普通字符上,比如下面實現效果為
黑̮̑Unicode 碼值通常使用 U+N(16 進位N 代表碼值)表示,比如 A 的碼值為 U+0041。
在 HTML 中 Unicode 可以使用 &#N;(十進位,N 代表碼值)表示。
在 JS 中 Unicode 中需要使用] \uN(16 進位N 代表碼值)表示。
只要我們在普通字符多複製幾個這類附加字符,就可以形成上述「擊穿」效果。
還記得上面說的泰文嗎,曾經有一段時間,貼吧很流行一種噴射文,比如下面的效果。
往左噴、往右噴、左右互噴這種噴射文實際原理就是利用泰文中聲調符號附加在其他正常符號上。
不過現在這個效果貌似已經沒辦法再復現了,現在我們只能看到這樣的效果:
在一些老版本的系統/瀏覽器可能還能看到這種效果,知道的小夥伴留言區可以告知一下。
零寬字符Unicode 中還有一類格式字符,不可見,不可列印,主要作用於調整字符的顯示格式,所以我們將其稱為零寬字符。
零寬字符主要有以下幾類:
零寬度空格符 (zero-width space) U+200B : 用於較長單詞的換行分隔。
零寬度非斷空格符 (zero width no-break space) U+FEFF : 用於阻止特定位置的換行分隔。
零寬度連字符 (zero-width joiner) U+200D : 用於阿拉伯文與印度語系等文字中,使不會發生連字的字符間產生連字效果。
零寬度斷字符 (zero-width non-joiner) U+200C : 用於阿拉伯文、德文、印度語系等文字中,阻止會發生連字的字符間的連字效果。
左至右符 (left-to-right mark) U+200E : 用於在混合文字方向的多種語言文本中(例:混合左至右書寫的英語與右至左書寫的希伯來語),規定排版文字書寫方向為左至右。
右至左符 (right-to-left mark) U+200F : 用於在混合文字方向的多種語言文本中,規定排版文字書寫方向為右至左。
利用零寬字符不可見的特性,我們也可以玩出一些騷效果。
空白微博發布微博的時候,如果內容都是空格,將沒辦法發布。
但是如果我們將零寬字符,比如說「零寬度空格符 U+200B」複製到微博,這樣我們就可以發布空白微博。
我們可以利用 Chrome 瀏覽器的控制臺複製零寬字符,操作方式如下:
發布效果如下:
真的沒有改 HTML 導致的.jpg隱形水印對於一些內部論壇或者說小說網站來說,可以通過零寬字符在帖子或小說內容中嵌入隱形水印。
當這些內容被一些爬蟲複製到其他網站時,我們就可以通過隱形水印,輕鬆查找是哪位用戶洩漏內容。
隱形水印主要原理就是將用戶信息比如用戶名,通過一定算法轉成零寬字符,這樣普通用戶瀏覽時完全看不到這個水印。
如果內容被複製到其他網站,隱形水印也被複製,只要找到這個水印,將這些零寬字符反轉成用戶名即可。
下面展示一種轉換方法,JS 代碼主要參考以下 Github 項目:
https://github.com/umpox/zero-width-detection
隱形水印生成方法
第一步我們需要將明文字符串中每個字符都轉成二進位串。
// 每個字符轉為二進位,用空格分隔
const textToBinary = username => (
username
.split('')
// charCodeAt 將字符轉成相應的 Unicode 碼值
.map(char => char.charCodeAt(0).toString(2))
.join(' ')
);示例如下:
第二步,將二進位串轉為零度字符串,轉換規則如下:
1 轉換為 \u200b 零寬度字符(zero-width space)0 轉換為 \u200c 零寬度斷字符(zero-width non-joiner)其他(剩餘就是空格) 轉換為 \u200d 零寬度連字符 (zero-width joiner)最後使用 \ufeff 零寬度非斷空格符 (zero width no-break space) 作為分隔符const binaryToZeroWidth = binary => (
binary.split('').map((binaryNum) => {
const num = parseInt(binaryNum, 10);
if (num === 1) {
return '\u200b'; // \u200b 零寬度字符(zero-width space)
} else if(num===0) {
return '\u200c'; // \u200c 零寬度斷字符(zero-width non-joiner)
}
return '\u200d'; // \u200d 零寬度連字符 (zero-width joiner)
}).join('\ufeff') // \ufeff 零寬度非斷空格符 (zero width no-break space)
);最終加密方法如下:
const encode = username => {
const binaryUsername = textToBinary(username);
const zeroWidthUsername = binaryToZeroWidth(binaryUsername);
return zeroWidthUsername;
};使用加密方法將明文字符串加密之後,加密字符串肉眼是看不到了,但是實際還是存在的。
實際上,如果我們將加密之後字符串複製到 👉BEJSON 網站,就可以看到字符。
另外你還可以把加密字符串複製到 IDEA 中,可以看到相應的 Unicode 編碼值。解密隱形水印
知道了加密的方式,解密其實就很簡單,我們只要按照相反的步驟來就可以了。
第一步,將隱形水印按照以下規則轉換為二進位串。轉換規則如下:
const zeroWidthToBinary = string => (
string.split('\ufeff').map((char) => { // \ufeff 零寬度非斷空格符 (zero width no-break space)
if (char === '\u200b') { // \u200b 零寬度字符(zero-width space)
return '1';
} else if(char === '\u200c') { // \u200c 零寬度斷字符(zero-width non-joiner)
return '0';
}
return ' ';
}).join('')
);調用該方法,隱形水印轉成二進位串。
第二步,將二進位再轉為相應的字符。
const binaryToText = string => (
// fromCharCode 二進位轉化
string.split(' ').map(num => String.fromCharCode(parseInt(num, 2))).join('')
);最終解密方法如下:
const decode = zeroWidthUsername => {
const binaryUsername = zeroWidthToBinary(zeroWidthUsername);
const textUsername = binaryToText(binaryUsername);
return textUsername;
};解密示例如下:
短網址
我們常用的短網址,域名後面會跟上一串隨機串,從而實現短網址到長網址的映射。比如以下網址:
https://sourl.cn/iLyn9S
我們利用零寬字符也可以實現短網址的效果,比如下面這個網站,就可以生成這類短網址。
https://zws.im/
可以看到這個短網址後面看不到任何字符,實際上這後面跟著一串零寬字符。當瀏覽器訪問該短網址時,後端程序只要反解密後面的零寬字符,拿到相應的網址,然後再做跳轉就可以到指定的網站。
反解密的原理可以參考上面隱形水印的代碼。
小心零寬字符日常開發過程中,我們有時需要從一些文件中讀取文本內容,然後做相應的處理。
有時候我們可能會碰到一些詭異的現象,比如我們之前碰到的例子。
後臺程序從 Excel 讀取文本內容,然後程序中判斷讀取的文本內容是否與指定的字符串相等。
然後當我們讀取一份 Excel 內容後,發現這段比較邏輯怎麼也通過不了。本來以為是 Excel 內容存在空格什麼的,但是打開 Excel 仔細一看,跟指定字符串一模一樣,並沒有什麼其他字符。
第一次碰到這種例子,沒有什麼經驗,真的排查了很久,到最後都有點懷疑人生了。最後無意間將文本內容複製到了 IDEA 中,才發現這裡混雜著零寬字符!
如果各位小夥伴也碰到這類問題,不妨複製文本內容,然後到 IDEA 中查看是否存在某些看不見的字符~
參考連結https://juejin.im/post/5d3f01e7f265da03c23ead69http://zero.rovelast.com/https://imweb.io/topic/5a08a5c7ef79bc941c30d8dd