不同的人對 Javascript 代碼的保護有不同的看法;有的人辛苦努力的代碼,卻可以被競爭對手輕易獲得,他們就非常希望能有保護 Javascript 代碼的方案,但現(xiàn)有的方案可能無法滿足他們的要求;很多人認為 Javascript 語言很簡單,Javascript 代碼沒有保護的價值,可能是他們的代碼確實簡單,或者他們并不了解 Javascript 語言強大的功能;還有的人認為現(xiàn)在都開源了,還保護代碼干什么,當然開源的人是值得敬佩的,但對別人的代碼的開源要求,卻不是合理的。
為了提高用戶的體驗,出現(xiàn)了 Web 2.0 技術(shù),并隨著 AJAX 和富界面技術(shù)的發(fā)展,Javascript 在 Web 應用上的重要性越來越高,Javascript 代碼的復雜性、功能和技術(shù)含量也越來越高,對Javascript 代碼保護的需要也越來越迫切。
Javascript 在線混淆器的目的是為 Javascript 代碼保護的需求,提供一種全新的綜合解決方案,包括編碼規(guī)則和免費的在線混淆器。
混淆和加密的區(qū)別
很多人將這兩者混在一起討論,實際上兩者的目的有一定的區(qū)別,采取的手段也有很大的不同。加密主要是為了防止未經(jīng)授權(quán)的使用,對這種情況即使破解了加密,也只能非法使用,并不一定能獲得軟件的代碼邏輯;但對于腳本來說,防止對代碼進行訪問的措施,也屬于加密,對這種情況,破解了加密,就獲得了代碼;而混淆是在無法阻止他人獲取代碼的情況下,采取的保護代碼的邏輯不被他人理解的措施;對于混淆的代碼,他人很難理解,無法進行修改和重新應用;
對于生成機器碼的語言,比如 C 語言,只需要考慮未經(jīng)授權(quán)的訪問,幾乎不需考慮代碼的保護;因為對編譯后的軟件,只能反匯編為匯編語言代碼,幾乎無法分析出代碼的邏輯。
對于生成中間代碼的語言,比如 Java 和 C#,即需要考慮未經(jīng)授權(quán)的訪問,又需考慮代碼的保護;;因為對編譯后的軟件,可以很容易的反編譯為較高級的語言,從而了解到代碼中的邏輯,并較容易的破解加密。而混淆后,即難于理解代碼的邏輯,也不易找到加密點所在。
對于腳本語言,比如 Javascript,只能混淆,難以加密;因為腳本都是明文存在的,很容易調(diào)試的,通過跟蹤可以較容易的破解上面兩種目的的加密。但是混淆后的代碼是難于理解代碼的邏輯的。
我們只涉及到對 Javascript 腳本進行混淆,而不涉及加密;對于涉及到 Javascript 的系統(tǒng)的加密,我們建議不要將加密點放在 Javascript 腳本內(nèi),而是放在服務端的編譯程序內(nèi),因為編譯程序的加密可以采用更多的保護方式,加密的強度也更高。
我們首先要分析 Javascript 語言和混淆相關(guān)的特點,和現(xiàn)有的混淆產(chǎn)品的不足,然后再提出我們對 Javascript 代碼混淆的解決方案,最后是我們的 Javascript 在線混淆器。
Javascript 語言和混淆相關(guān)的特性
Javascript 是一種解釋執(zhí)行的腳本語言,相對編譯類型的語言有很多自身的特性,而其中一些特性會對代碼混淆帶來很大的困難。
無法定義類的屬性和方法的名稱是否需要被混淆
Javascript 是一種基于原型的語言,沒有嚴格的類型定義。在自定義的類中,對于需要外部訪問的屬性和方法,不能進行混淆;對于內(nèi)部訪問的屬性和方法,需要進行混淆;但Javascript 語言本身,無法對屬性和方法進行這樣的區(qū)分。為此我們要尋找一種變通的機制來識別屬性和方法的名稱是否需要混淆。
存在大量的系統(tǒng)定義的核心的和客戶端的方法和屬性不能被混淆
Javascript 語言本身定義了大量的核心的類、方法和屬性;瀏覽器中也定義了大量的客戶端的類、方法和屬性;這些類、方法和屬性都不能夠被混淆,然而這些類、方法和屬性的數(shù)量太大,無法通過枚舉來避免混淆;為此我們需要尋找一種方法來標識這些類、屬性和方法。
無法定義全局變量是否需要被混淆
全局變量是 window 對象的屬性,局部變量是函數(shù)對象的屬性;所有的局部變量都是可以和應該被混淆的,而全局變量有的需要混淆,有的不能混淆;但全局變量和局部變量的表現(xiàn)形式是一樣的,難以區(qū)分;而且全局變量本身更無法定義是否需要被混淆。為此我們要找到一種方法來區(qū)分不能混淆的全局變量,和需要混淆的全局變量及局部變量。
Javascript 語言的這些特點,都對代碼的混淆帶來了很大的困難,如果不解決這幾個問題,Javascript 代碼的混淆就缺少實用的價值。
現(xiàn)有 Javascript 混淆產(chǎn)品的問題
當我們需要混淆 Javascipt 代碼的時候,首先考察了市面上現(xiàn)有的產(chǎn)品,和一些論壇里對混淆的思路,但這些產(chǎn)品和思路都不能滿足我們的要求。
有一個商品化的 Javascript 混淆產(chǎn)品,采用了和一種 C# 混淆工具相似的混淆方式,分析了代碼里所有的標識符,對一些系統(tǒng)預設的標識符不混淆,對其他的進行混淆,同時提供用戶對標識符的混淆進行選擇和配置;這個產(chǎn)品的功能很多很復雜,但有一個很大的問題,就是預設的標識符有限,對于代碼中用到的大量的系統(tǒng)定義的屬性和方法,會進行混淆,為此需要自己手工配置,避免對這些屬性和方法的混淆,這對于大型的系統(tǒng)幾乎是一個不可能完成的任務。
有一些論壇里也討論到混淆的思路,包括一些示例,這些思路更多的是改變標識符的表現(xiàn)形式,有的是用編碼字符串的關(guān)聯(lián)數(shù)組替換屬性,比如將 xx.dd 替換為 xx["\x64\x64"];更復雜的是把 "\x64\x64" 之類保存到字符串數(shù)組,然后調(diào)用字符串數(shù)組作為關(guān)聯(lián)數(shù)組的下標;這種思路可以避免上面的問題,但有一個更大的問題,就是混淆是可逆的,被混淆的標識符僅僅是被轉(zhuǎn)換成了16進制的形式,可以很容易的恢復。
正是現(xiàn)有產(chǎn)品的不足,促使我們不得不研究自己的解決方案。我們的解決方案也是經(jīng)過了幾個版本,一開始的版本要復雜的多,花費了很大的工作量,但結(jié)果并不理想;幾經(jīng)修改才找到現(xiàn)有的解決方案;雖然開始的大量工作,最后幾乎都廢棄了,但沒有前面的工作,也就沒有后面的結(jié)果;所以即使您可能會認為我們的方案簡單,那也只是我們努力的結(jié)果,而不是過程;而且簡單的東西,往往是有效的。
Javascript 代碼混淆綜合解決方案
通過前面對 Javascript 的特性和相關(guān)混淆產(chǎn)品的分析,使我們認識到如果僅僅是在混淆器上下功夫是不夠的;因為 Javascript 語言本身對混淆的功能有很大的限制,無法解決。為此我們設計了一個綜合的解決方案,就是 Javascript 在線混淆器規(guī)則,只要是按照規(guī)則編寫的 Javascipt 代碼,都能使用 Javascript 在線混淆器混淆進行混淆。
Javascript 在線混淆器的規(guī)則并不復雜,但能夠解決 Javascript 語言本身的特性和其他混淆產(chǎn)品遇到的問題。
規(guī)則一、所有用 window 約束的類、變量和函數(shù)都不混淆,其他的類、變量和函數(shù)都混淆。
全局的類、變量和函數(shù)本身都是 window 的屬性,用不用 window 約束,從邏輯的角度是一樣的。但我們可以借用 window 的約束來區(qū)分對全局的類、變量和函數(shù)是否需要進行混淆。
用 window 的約束必須是前后一致的,不但包括類、變量和函數(shù)的定義,也包括類、變量和函數(shù)的調(diào)用。
局部的類、變量和函數(shù),因為沒有 window 約束,所以都是混淆的。
類型 | 混淆 | 不混淆 |
類定義 | function Class1(){...} | window.Class1 = function(){...} |
函數(shù)定義 | function Method1(){...} | window.Method1 = function(){...} |
變量定義 | var Param1 = 1; | window.Param1 = 1; |
生成類的實例 | var object1 = new Class1(); | var object1 = new window.Class1(); |
函數(shù)調(diào)用 | Method1(); | window.Method1() |
變量引用 | var newParam = Param1; | var newParam = window.Param1; |
規(guī)則二、所有以小寫字符開頭的屬性和方法都不混淆,以其他字母開頭的屬性和方法都混淆,用 window 約束的屬性和方法應用規(guī)則一。
JavaScript 核心和客戶端中有大量的系統(tǒng)定義的方法和屬性不能被混淆,而這些方法和屬性絕大多數(shù)都是以小寫字母開始的,本規(guī)則保證了系統(tǒng)定義的方法和屬性不被混淆。在 Javascript 客戶端中僅有極少數(shù)的系統(tǒng)定義的以大寫字符起始的方法和屬性,對于這種情況,可以采用關(guān)聯(lián)數(shù)組的方式避免被混淆,比如 object1["Method1"]();此方法也適用于第三方控件中可能會有的以大寫字符起始的方法和屬性的情況。
此規(guī)則也使我們可以在自定義的類中標識方法和屬性是否被混淆,對于需要外部調(diào)用不能混淆的方法和屬性,采用小寫字母起始,對于內(nèi)部的方法和屬性,采用其他字母起始。
類型 | 混淆 | 不混淆 |
類方法定義 | Class1.Method1 = function(){...} | Class1.method1 = function(){...} Class1["Method1"] = function(){...} |
對象方法定義 | Class1.prototype.Method1 = function(){...} | Class1.prototype.method1 = function(){...} Class1.prototype["Method1"] = function(){...} |
類屬性定義 | Class1.Prop1 = 1; | Class1.prop1 = 1; Class1["Prop1"] = 1; |
對象屬性定義 | object1.Prop1 = 1; | object1.prop1 = 1; object1["Prop1"] = 1; |
類方法調(diào)用 | Class1.Method1(); | Class1.method1 (); Class1["Method1"](); |
對象方法調(diào)用 | object1.Method1(); | object1.method1 (); object1["Method1"](); |
更多相關(guān)教程請訪問 JavaScript視頻教程
聲明:本網(wǎng)頁內(nèi)容旨在傳播知識,若有侵權(quán)等問題請及時與本網(wǎng)聯(lián)系,我們將在第一時間刪除處理。TEL:177 7030 7066 E-MAIL:11247931@qq.com