一、引入
1.1、在一些網(wǎng)頁中,往往會有這樣的需求:防止用戶通過爬蟲手段快速批量獲取需要顯示但是又極為敏感的數(shù)據(jù)。
- 比如:電商網(wǎng)站的價格、文獻資料、具有版權性質的圖庫文庫等。
- 這時候往往可以通過 字體混淆 技術來達到一定的防范效果。
-
例如:(圖片來自網(wǎng)絡)
0adb84d965924fa18d2684bd14266283.png
1.2、原理解釋
- 首先,字體混淆僅僅是增加了爬蟲困難,通過恢復字體等手段依然能獲得原始文本。
- 字體文件內部存在這一種字符與字形的對應關系,或者說就是字符unicode與字形編碼的對應關系。我們只要把這個對應關系偏移或打亂,使用打亂后的字符+打亂后的字體文件,即可在web端不影響顯示的情況下達到混淆效果。
二、實現(xiàn)代碼
2.1、本代碼實現(xiàn)了如下功能:
根據(jù)需要截取字體文件
修改字符與字形的關系映射
保存新字體文件和輸出混淆后的字符串
-
python實現(xiàn):
##### # Created by 王圣滔[賢圣] # Email: w778899wst@live.cn ##### from fontTools.ttLib import TTFont from fontTools import subset """ 根據(jù)字符需要裁剪 字體文件內字符-字形映射關系的修改 輸出編輯過的字體文件+偏移后的文本 """ # 需要混淆的字符串 myStr = "今天你真好看" # 加載字體文件: font = TTFont('./ttf/Alibaba-PuHuiTi-Light.ttf') # 截取字符串內字符使用到的字體(為了減小體積) subsetter = subset.Subsetter() subsetter.populate(text=myStr) subsetter.subset(font) # 獲得字符、字形映射 cmap = font.getBestCmap() print("--------------原始映射關系-----------------") print(cmap) # 修改映射關系,這里從文本的第一個字符開始,依次替換為A、B、C、D及往后字符的unicode # 實際項目中可以根據(jù)自己的喜好去編寫混淆算法,這里僅做基本演示 baseCode = 0x0041 # 初始code newStr = "" # 新的偏移后文本 oldAndNewKeyMap = {} #存放修改前、修改后的key對應關系,以便在發(fā)生字符重復時找到原先的key再修改新key for st in myStr: code = ord(st) # 原始字符的unicode try: cmap[baseCode] = cmap.pop(code) # 刪除原有映射,并以新key存儲映射 newStr += chr(baseCode) # 連接新文本 oldAndNewKeyMap[code] = baseCode # 錄入新舊code baseCode = baseCode + 0x0001 except Exception as err: print("發(fā)生異常:Unicode %s 字符已做過偏移映射" % err) newCode = oldAndNewKeyMap[code] newStr += chr(newCode) # 連接新文本 continue print("--------------修改后的映射關系-------------") print(cmap) print("--------------修改后偏移文本-------------") print(newStr) # 保存新ttf文件: font.save('./output/Alibaba-PuHuiTi-Light-cut-change-test.ttf') # 保存woff等其他文件 # options = subset.Options() # options.flavor = 'woff' # subset.save_font(font, './output/Alibaba-PuHuiTi-Light-min.woff', options) -
web端操作:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <style> <!--這里要定義混淆后的字體文件樣式--> @font-face { font-family: "myFont"; src: url("./output/Alibaba-PuHuiTi-Light-cut-change-test.ttf") format("truetype"); } </style> </head> <body> <h3>原文本</h3> <p>今天你真好看</p> <h3>混淆文本</h3> <p>ABCDEF</p> <h3>混淆文本復原</h3> <!--這里設置了該字體的樣式才能生效--> <p style="font-family: myFont">ABCDE</p> </body> </html>
2.2、上效果
-
控制臺輸出:
575b0dcd6cf24b10b64b47743f0caf42.png -
網(wǎng)頁內容:
8adca6189fe3494e85e42406bd73baf2.png
三、fontTools庫的使用
3.1、開始之前,建議先了解ttf字體內部結構
- 見Apple或Microsoft官網(wǎng)查看文檔(由這兩家公司制定的規(guī)范)
- https://developer.apple.com/fonts/TrueType-Reference-Manual/
- https://docs.microsoft.com/zh-cn/typography/about
from fontTools.ttLib.ttFont import TTFont
from fontTools import subset
3.1、使用
-
打開字體文件
font = TTFont('TestFont.ttf') -
轉存xml文件(方便查看內部結構使用)
font.saveXML('TestFont.xml') -
字體拆分截取
# 截取包含“你好嘿!”幾個字符的字體內容 subsetter = subset.Subsetter() subsetter.populate(text="你好嘿嘿!") subsetter.subset(font) -
保存與其他格式保存
# 保存新ttf文件: font.save('TestFont-new.ttf') # 保存woff等其他文件 options = subset.Options() options.flavor = 'woff' subset.save_font(font, 'TestFont.woff', options) -
獲取所有節(jié)點名
print(font.keys())b3deab7d41364c3baa62fb013b3bb0af.png -
獲取cmap節(jié)點unicode與name值映射(字符和字形映射)
print(font.getBestCmap())5e8f8f9a90584e768925b24f47875162.png4b2f3d8118ab48adb21f506b337d468a.png





