個人認為,js的不可讀化處理分為三個方面:壓縮(compression)、混淆(obfuscation) 和加密(encryption)。 (不可讀化處理,這是我自己發明的術語,壹切會增加代碼不可讀性的代碼轉換, 都可以這麽叫,“增加代碼不可讀性”可能是代碼轉換的結果或者目的).
1. 壓縮
這壹操作的目的,是讓最終代碼傳輸量 (不代表代碼量, 也不代表文件體積)盡可能小。壓縮js的工具,常見的有:YUI Compressor、UglifyJS、Google Closure Compiler 等。
通常在代碼壓縮的過程中,只改變代碼的語法,代碼的語義和控制流不會有太大改變。
常見做法是把局部變量縮短化,把壹些運算進行等價替換等。代碼壓縮對於代碼保護有壹些幫助,但由於語義和控制流基本沒變,起不了太大作用。
在壓縮層面上,代碼不可讀只是壹種附帶傷害,不是最終目的。
2. 混淆
這壹操作的目的,是讓代碼盡可能地不可讀,主要用作代碼保護。
讓代碼不可讀,增加分析的難度,這是唯壹目的。混淆過後文件體積變大壹倍也沒關系,代碼量變多也沒關系,運算慢50% 也沒關系。
常見的做法有:分離常量、打亂控制流、增加無義代碼、檢查運行環境如果不對就罷工,等等。
在混淆層面上,代碼不可讀是最終目的。
值得壹提的是,Google Closure Compiler 的 Advance Level Compression 會壓縮類和對象的成員,其壓縮結果很難分析,也可以認為是壹種混淆,但兼容性不太好。
廣告時間:我寫的 js混淆器,中文名叫 “看起來很厲害的 JS 編譯器”, 英文名叫做 The Impressive JS.Segment.Compiler , 看起來很厲害的 JS 編譯器 。
3. 加密
說實話我很難對加密做壹個定義,因為加密在Web界有太多歧義了。
有加密就有解密,意味著加密操作可逆,密文可以明文化。
就這樣看來,在Web界,可以稱之為加密的東西包括:HTTPS傳輸、JavaScript實現對稱加密或者不對稱加密等等。
這樣看來,不可逆的代碼壓縮和混淆就不能列入加密這個範疇了。
非要找壹個可以稱之為加密,又經常被人誤解為壓縮和混淆的東西,Dean Edwards 的 Dean Packer/Unpacker 可以拿來做個例子。
比如我們把 var num=1;alert(num);
輸入 Dean Packer,pack 壹下,得到這麽壹串東西,是不是看著非常像被壓縮和混淆過的代碼?
把上面那串意義不明物拿來 unpack 壹下,得到了原文。
實際上 Dean Packer 只是對源碼進行了壹個字符串變換,沒有深入到代碼語法層面,妳可以拿 "Hello world, 妳好師姐" 來試試。
用Online JavaScript beautifier 能輕松把這串東西還原為 “Hello world, 妳好師姐”。
可以看出,代碼加密意味著:將代碼明文進行可逆的變換(加密),生成密文;將密文進行逆變換(解密),可以還原明文;最終運行環境運行的是解密代碼。
結語
實際上大家對壓縮、混淆、加密這三個概念還是挺不清晰的,我在這裏說壹些個人見解,希望有幫助。
在現實項目中,我是多種手段結合的:
對於不需要做代碼保護的項目,比如個人博客,做代碼壓縮,加快載入速度,這就夠了。
對於需要做壹些代碼保護,防止抄襲的項目,可以在源碼中加入壹些開發者的信息和防護代碼,然後混淆和壓縮。很不幸的是,我這方面總是做得不太好,防君子防不了小人啊哈哈。
對於需要嚴格加密的項目,可以用 混淆、壓縮、加密、簽名檢查 等多種手段,這我就不清楚了,等大嬸來補充。