;????? Java程序的源代碼很容易被別人偷看 只要有一個反編譯器 任何人都可以分析別人的代碼 本文討論如何在不修改原有程序的情況下 通過加密技術保護源代碼
創(chuàng)新互聯(lián)是一家專業(yè)提供通許企業(yè)網站建設,專注與成都網站建設、成都網站制作、HTML5、小程序制作等業(yè)務。10年已為通許眾多企業(yè)、政府機構等服務。創(chuàng)新互聯(lián)專業(yè)網站建設公司優(yōu)惠進行中。
一 為什么要加密?
對于傳統(tǒng)的C或C++之類的語言來說 要在Web上保護源代碼是很容易的 只要不發(fā)布它就可以 遺憾的是 Java程序的源代碼很容易被別人偷看 只要有一個反編譯器 任何人都可以分析別人的代碼 Java的靈活性使得源代碼很容易被竊取 但與此同時 它也使通過加密保護代碼變得相對容易 我們唯一需要了解的就是Java的ClassLoader對象 當然 在加密過程中 有關Java Cryptography Extension(JCE)的知識也是必不可少的
有幾種技術可以 模糊 Java類文件 使得反編譯器處理類文件的效果大打折扣 然而 修改反編譯器使之能夠處理這些經過模糊處理的類文件并不是什么難事 所以不能簡單地依賴模糊技術來保證源代碼的安全
我們可以用流行的加密工具加密應用 比如PGP(Pretty Good Privacy)或GPG(GNU Privacy Guard) 這時 最終用戶在運行應用之前必須先進行解密 但解密之后 最終用戶就有了一份不加密的類文件 這和事先不進行加密沒有什么差別
Java運行時裝入字節(jié)碼的機制隱含地意味著可以對字節(jié)碼進行修改 JVM每次裝入類文件時都需要一個稱為ClassLoader的對象 這個對象負責把新的類裝入正在運行的JVM JVM給ClassLoader一個包含了待裝入類(比如java lang Object)名字的字符串 然后由ClassLoader負責找到類文件 裝入原始數(shù)據(jù) 并把它轉換成一個Class對象
我們可以通過定制ClassLoader 在類文件執(zhí)行之前修改它 這種技術的應用非常廣泛??在這里 它的用途是在類文件裝入之時進行解密 因此可以看成是一種即時解密器 由于解密后的字節(jié)碼文件永遠不會保存到文件系統(tǒng) 所以竊密者很難得到解密后的代碼
由于把原始字節(jié)碼轉換成Class對象的過程完全由系統(tǒng)負責 所以創(chuàng)建定制ClassLoader對象其實并不困難 只需先獲得原始數(shù)據(jù) 接著就可以進行包含解密在內的任何轉換
Java 在一定程度上簡化了定制ClassLoader的構建 在Java 中 loadClass的缺省實現(xiàn)仍舊負責處理所有必需的步驟 但為了顧及各種定制的類裝入過程 它還調用一個新的findClass方法
這為我們編寫定制的ClassLoader提供了一條捷徑 減少了麻煩 只需覆蓋findClass 而不是覆蓋loadClass 這種方法避免了重復所有裝入器必需執(zhí)行的公共步驟 因為這一切由loadClass負責
不過 本文的定制ClassLoader并不使用這種方法 原因很簡單 如果由默認的ClassLoader先尋找經過加密的類文件 它可以找到;但由于類文件已經加密 所以它不會認可這個類文件 裝入過程將失敗 因此 我們必須自己實現(xiàn)loadClass 稍微增加了一些工作量
二 定制類裝入器
每一個運行著的JVM已經擁有一個ClassLoader 這個默認的ClassLoader根據(jù)CLASSPATH環(huán)境變量的值 在本地文件系統(tǒng)中尋找合適的字節(jié)碼文件
應用定制ClassLoader要求對這個過程有較為深入的認識 我們首先必須創(chuàng)建一個定制ClassLoader類的實例 然后顯式地要求它裝入另外一個類 這就強制JVM把該類以及所有它所需要的類關聯(lián)到定制的ClassLoader Listing 顯示了如何用定制ClassLoader裝入類文件
【Listing 利用定制的ClassLoader裝入類文件】
以下是引用片段
// 首先創(chuàng)建一個ClassLoader對象 ClassLoader myClassLoader = new myClassLoader(); // 利用定制ClassLoader對象裝入類文件 // 并把它轉換成Class對象 Class myClass = myClassLoader loadClass( mypackage MyClass ); // 最后 創(chuàng)建該類的一個實例 Object newInstance = myClass newInstance(); // 注意 MyClass所需要的所有其他類 都將通過 // 定制的ClassLoader自動裝入
如前所述 定制ClassLoader只需先獲取類文件的數(shù)據(jù) 然后把字節(jié)碼傳遞給運行時系統(tǒng) 由后者完成余下的任務
ClassLoader有幾個重要的方法 創(chuàng)建定制的ClassLoader時 我們只需覆蓋其中的一個 即loadClass 提供獲取原始類文件數(shù)據(jù)的代碼 這個方法有兩個參數(shù) 類的名字 以及一個表示JVM是否要求解析類名字的標記(即是否同時裝入有依賴關系的類) 如果這個標記是true 我們只需在返回JVM之前調用resolveClass
【Listing ClassLoader loadClass()的一個簡單實現(xiàn)】
以下是引用片段
public Class loadClass( String name boolean resolve ) throws ClassNotFoundException { try { // 我們要創(chuàng)建的Class對象 Class clasz = null; // 必需的步驟 如果類已經在系統(tǒng)緩沖之中 // 我們不必再次裝入它 clasz = findLoadedClass( name ); if (clasz != null) return clasz; // 下面是定制部分 byte classData[] = /* 通過某種方法獲取字節(jié)碼數(shù)據(jù) */; if (classData != null) { // 成功讀取字節(jié)碼數(shù)據(jù) 現(xiàn)在把它轉換成一個Class對象 clasz = defineClass( name classData classData length ); } // 必需的步驟 如果上面沒有成功 // 我們嘗試用默認的ClassLoader裝入它 if (clasz == null) clasz = findSystemClass( name ); // 必需的步驟 如有必要 則裝入相關的類 if (resolve clasz != null) resolveClass( clasz ); // 把類返回給調用者 return clasz; } catch( IOException ie ) { throw new ClassNotFoundException( ie toString() ); } catch( GeneralSecurityException gse ) { throw new ClassNotFoundException( gse toString() ); } }
Listing 顯示了一個簡單的loadClass實現(xiàn) 代碼中的大部分對所有ClassLoader對象來說都一樣 但有一小部分(已通過注釋標記)是特有的 在處理過程中 ClassLoader對象要用到其他幾個輔助方法
findLoadedClass 用來進行檢查 以便確認被請求的類當前還不存在 loadClass方法應該首先調用它
defineClass 獲得原始類文件字節(jié)碼數(shù)據(jù)之后 調用defineClass把它轉換成一個Class對象 任何loadClass實現(xiàn)都必須調用這個方法
findSystemClass 提供默認ClassLoader的支持 如果用來尋找類的定制方法不能找到指定的類(或者有意地不用定制方法) 則可以調用該方法嘗試默認的裝入方式 這是很有用的 特別是從普通的JAR文件裝入標準Java類時
resolveClass 當JVM想要裝入的不僅包括指定的類 而且還包括該類引用的所有其他類時 它會把loadClass的resolve參數(shù)設置成true 這時 我們必須在返回剛剛裝入的Class對象給調用者之前調用resolveClass
三 加密 解密
Java加密擴展即Java Cryptography Extension 簡稱JCE 它是Sun的加密服務軟件 包含了加密和密匙生成功能 JCE是JCA(Java Cryptography Architecture)的一種擴展
JCE沒有規(guī)定具體的加密算法 但提供了一個框架 加密算法的具體實現(xiàn)可以作為服務提供者加入 除了JCE框架之外 JCE軟件包還包含了SunJCE服務提供者 其中包括許多有用的加密算法 比如DES(Data Encryption Standard)和Blowfish
為簡單計 在本文中我們將用DES算法加密和解密字節(jié)碼 下面是用JCE加密和解密數(shù)據(jù)必須遵循的基本步驟
步驟 生成一個安全密匙 在加密或解密任何數(shù)據(jù)之前需要有一個密匙 密匙是隨同被加密的應用一起發(fā)布的一小段數(shù)據(jù) Listing 顯示了如何生成一個密匙 【Listing 生成一個密匙】
以下是引用片段
// DES算法要求有一個可信任的隨機數(shù)源 SecureRandom sr = new SecureRandom(); // 為我們選擇的DES算法生成一個KeyGenerator對象 KeyGenerator kg = KeyGenerator getInstance( DES ); kg init( sr ); // 生成密匙 SecretKey key = kg generateKey(); // 獲取密匙數(shù)據(jù) byte rawKeyData[] = key getEncoded(); /* 接下來就可以用密匙進行加密或解密 或者把它保存 為文件供以后使用 */ doSomething( rawKeyData );??步驟 加密數(shù)據(jù) 得到密匙之后 接下來就可以用它加密數(shù)據(jù) 除了解密的ClassLoader之外 一般還要有一個加密待發(fā)布應用的獨立程序(見Listing ) 【Listing 用密匙加密原始數(shù)據(jù)】
以下是引用片段
// DES算法要求有一個可信任的隨機數(shù)源 SecureRandom sr = new SecureRandom(); byte rawKeyData[] = /* 用某種方法獲得密匙數(shù)據(jù) */; // 從原始密匙數(shù)據(jù)創(chuàng)建DESKeySpec對象 DESKeySpec dks = new DESKeySpec( rawKeyData ); // 創(chuàng)建一個密匙工廠 然后用它把DESKeySpec轉換成 // 一個SecretKey對象 SecretKeyFactory keyFactory = SecretKeyFactory getInstance( DES ); SecretKey key = keyFactory generateSecret( dks ); // Cipher對象實際完成加密操作 Cipher cipher = Cipher getInstance( DES ); // 用密匙初始化Cipher對象 cipher init( Cipher ENCRYPT_MODE key sr ); // 現(xiàn)在 獲取數(shù)據(jù)并加密 byte data[] = /* 用某種方法獲取數(shù)據(jù) */ // 正式執(zhí)行加密操作 byte encryptedData[] = cipher doFinal( data ); // 進一步處理加密后的數(shù)據(jù) doSomething( encryptedData );??步驟 解密數(shù)據(jù) 運行經過加密的應用時 ClassLoader分析并解密類文件 操作步驟如Listing 所示 【Listing 用密匙解密數(shù)據(jù)】
// DES算法要求有一個可信任的隨機數(shù)源 SecureRandom sr = new SecureRandom(); byte rawKeyData[] = /* 用某種方法獲取原始密匙數(shù)據(jù) */; // 從原始密匙數(shù)據(jù)創(chuàng)建一個DESKeySpec對象 DESKeySpec dks = new DESKeySpec( rawKeyData ); // 創(chuàng)建一個密匙工廠 然后用它把DESKeySpec對象轉換成 // 一個SecretKey對象 SecretKeyFactory keyFactory = SecretKeyFactory getInstance( DES ); SecretKey key = keyFactory generateSecret( dks ); // Cipher對象實際完成解密操作 Cipher cipher = Cipher getInstance( DES ); // 用密匙初始化Cipher對象 cipher init( Cipher DECRYPT_MODE key sr ); // 現(xiàn)在 獲取數(shù)據(jù)并解密 byte encryptedData[] = /* 獲得經過加密的數(shù)據(jù) */ // 正式執(zhí)行解密操作 byte decryptedData[] = cipher doFinal( encryptedData ); // 進一步處理解密后的數(shù)據(jù) doSomething( decryptedData );
四 應用實例
前面介紹了如何加密和解密數(shù)據(jù) 要部署一個經過加密的應用 步驟如下
步驟 創(chuàng)建應用 我們的例子包含一個App主類 兩個輔助類(分別稱為Foo和Bar) 這個應用沒有什么實際功用 但只要我們能夠加密這個應用 加密其他應用也就不在話下
步驟 生成一個安全密匙 在命令行 利用GenerateKey工具(參見GenerateKey java)把密匙寫入一個文件 % java GenerateKey key data
步驟 加密應用 在命令行 利用EncryptClasses工具(參見EncryptClasses java)加密應用的類 % java EncryptClasses key data App class Foo class Bar class
該命令把每一個 class文件替換成它們各自的加密版本
步驟 運行經過加密的應用 用戶通過一個DecryptStart程序運行經過加密的應用 DecryptStart程序如Listing 所示 【Listing DecryptStart java 啟動被加密應用的程序】
以下是引用片段
import java io *; import java security *; import java lang reflect *; import javax crypto *; import javax crypto spec *; public class DecryptStart extends ClassLoader { // 這些對象在構造函數(shù)中設置 // 以后loadClass()方法將利用它們解密類 private SecretKey key; private Cipher cipher; // 構造函數(shù) 設置解密所需要的對象 public DecryptStart( SecretKey key ) throws GeneralSecurityException IOException { this key = key; String algorithm = DES ; SecureRandom sr = new SecureRandom(); System err println( [DecryptStart: creating cipher] ); cipher = Cipher getInstance( algorithm ); cipher init( Cipher DECRYPT_MODE key sr ); } // main過程 我們要在這里讀入密匙 創(chuàng)建DecryptStart的 // 實例 它就是我們的定制ClassLoader // 設置好ClassLoader以后 我們用它裝入應用實例 // 最后 我們通過Java Reflection API調用應用實例的main方法 static public void main( String args[] ) throws Exception { String keyFilename = args[ ]; String appName = args[ ]; // 這些是傳遞給應用本身的參數(shù) String realArgs[] = new String[args length ]; System arraycopy( args realArgs args length ); // 讀取密匙 System err println( [DecryptStart: reading key] ); byte rawKey[] = Util readFile( keyFilename ); DESKeySpec dks = new DESKeySpec( rawKey ); SecretKeyFactory keyFactory = SecretKeyFactory getInstance( DES ); SecretKey key = keyFactory generateSecret( dks ); // 創(chuàng)建解密的ClassLoader DecryptStart dr = new DecryptStart( key ); // 創(chuàng)建應用主類的一個實例 // 通過ClassLoader裝入它 System err println( [DecryptStart: loading +appName+ ] ); Class clasz = dr loadClass( appName ); // 最后 通過Reflection API調用應用實例 // 的main()方法 // 獲取一個對main()的引用 String proto[] = new String[ ]; Class mainArgs[] = { (new String[ ]) getClass() }; Method main = clasz getMethod( main mainArgs ); // 創(chuàng)建一個包含main()方法參數(shù)的數(shù)組 Object argsArray[] = { realArgs }; System err println( [DecryptStart: running +appName+ main()] ); // 調用main() main invoke( null argsArray ); } public Class loadClass( String name boolean resolve ) throws ClassNotFoundException { try { // 我們要創(chuàng)建的Class對象 Class clasz = null; // 必需的步驟 如果類已經在系統(tǒng)緩沖之中 // 我們不必再次裝入它 clasz = findLoadedClass( name ); if (clasz != null) return clasz; // 下面是定制部分 try { // 讀取經過加密的類文件 byte classData[] = Util readFile( name+ class ); if (classData != null) { // 解密 byte decryptedClassData[] = cipher doFinal( classData ); // 再把它轉換成一個類 clasz = defineClass( name decryptedClassData decryptedClassData length ); System err println( [DecryptStart: decrypting class +name+ ] ); } } catch( FileNotFoundException fnfe ) // 必需的步驟 如果上面沒有成功 // 我們嘗試用默認的ClassLoader裝入它 if (clasz == null) clasz = findSystemClass( name ); // 必需的步驟 如有必要 則裝入相關的類 if (resolve clasz != null) resolveClass( clasz ); // 把類返回給調用者 return clasz; } catch( IOException ie ) { throw new ClassNotFoundException( ie toString() ); } catch( GeneralSecurityException gse ) { throw new ClassNotFoundException( gse toString() ); } } }??對于未經加密的應用 正常執(zhí)行方式如下 % java App arg arg arg
對于經過加密的應用 則相應的運行方式為 % java DecryptStart key data App arg arg arg
DecryptStart有兩個目的 一個DecryptStart的實例就是一個實施即時解密操作的定制ClassLoader;同時 DecryptStart還包含一個main過程 它創(chuàng)建解密器實例并用它裝入和運行應用 示例應用App的代碼包含在App java Foo java和Bar java內 Util java是一個文件I/O工具 本文示例多處用到了它 完整的代碼請從本文最后下載
五 注意事項
我們看到 要在不修改源代碼的情況下加密一個Java應用是很容易的 不過 世上沒有完全安全的系統(tǒng) 本文的加密方式提供了一定程度的源代碼保護 但對某些攻擊來說它是脆弱的
雖然應用本身經過了加密 但啟動程序DecryptStart沒有加密 攻擊者可以反編譯啟動程序并修改它 把解密后的類文件保存到磁盤 降低這種風險的辦法之一是對啟動程序進行高質量的模糊處理 或者 啟動程序也可以采用直接編譯成機器語言的代碼 使得啟動程序具有傳統(tǒng)執(zhí)行文件格式的安全性
另外還要記住的是 大多數(shù)JVM本身并不安全 狡猾的黑客可能會修改JVM 從ClassLoader之外獲取解密后的代碼并保存到磁盤 從而繞過本文的加密技術 Java沒有為此提供真正有效的補救措施
lishixinzhi/Article/program/Java/hx/201311/25751
以下從技術角度就常見的保護措施 和常用工具來看看如何有效保護java代碼:1. 將java包裝成exe 特點:將jar包裝成可執(zhí)行文件,便于使用,但對java程序沒有任何保護。不要以為生成了exe就和普通可執(zhí)行文件效果一樣了。這些包裝成exe的程序運行時都會將jar文件釋放到臨時目錄,很容易獲取。常用的工具有exe4j、jsmooth、NativeJ等等。jsmooth生成的exe運行時臨時目錄在exe所在目錄中或是用戶臨時目錄 中;exe4j生成的exe運行時臨時目錄在用戶臨時目錄中;NativeJ生成的exe直接用winrar打開,然后用zip格式修復成一個jar文件,就得到了原文件。如果只是為了使用和發(fā)布方便,不需要保護java代碼,使用這些工具是很好的選擇。2. java混淆器特點:使用一種或多種處理方式將class文件、java源代碼進行混淆處理后生成新的class,使混淆后的代碼不易被反編譯,而反編譯后的代碼難以閱 讀和理解。這類混淆器工具很多,而且也很有成效。缺點:雖然混淆的代碼反編譯后不易讀懂,但對于有經驗的人或是多花些時間,還是能找到或計算出你代碼中隱藏的敏感內容,而且在很多應用中不是全部代碼都能混淆的,往往一些關鍵的庫、類名、方法名、變量名等因使用要求的限制反而還不能混淆。3. 隔離java程序到服務端特點:把java程序放到服務端,讓用戶不能訪問到class文件和相關配套文件,客戶端只通過接口訪問。這種方式在客戶/服務模式的應用中能較好地保護java代碼。缺點是:必須是客戶/服務模式,這種特點限制了此種方式的使用范圍;客戶端因為邏輯的暴露始終是較為薄弱的環(huán)節(jié),所以訪問接口時一般都需要安全性認證。4. java加密保護特點:自定義ClassLoader,將class文件和相關文件加密,運行時由此ClassLoader解密相關文件并裝載類,要起到保護作用必須自定 義本地代碼執(zhí)行器將自定義ClassLoader和加密解密的相關類和配套文件也保護起來。此種方式能很有效地保護java代碼。缺點:可以通過替換JRE包中與類裝載相關的java類或虛擬機動態(tài)庫截獲java字節(jié)碼。 jar2exe屬于這類工具。5. 提前編譯技術(AOT) 特點:將java代碼靜態(tài)編譯成本地機器碼,脫離通用JRE。此種方式能夠非常有效地保護java代碼,且程序啟動比通用JVM快一點。具有代表性的是GNU的gcj,可以做到對java代碼完全提前編譯,但gcj存在諸多局限性,如:對JRE 5不能完整支持、不支持JRE 6及以后的版本。由于java平臺的復雜性,做到能及時支持最新java版本和JRE的完全提前編譯是非常困難的,所以這類工具往往采取靈活方式,該用即時編譯的地方還是 要用,成為提前編譯和即時編譯的混合體。缺點:由于與通用JRE的差異和java運用中的復雜性,并非java程序中的所有jar都能得到完全的保護;只能使用此種工具提供的一個運行環(huán)境,如果工具更新滯后或你需要特定版本的JRE,有可能得不到此種工具的支持。 Excelsior JET屬于這類工具。6. 使用jni方式保護特點:將敏感的方法和數(shù)據(jù)通過jni方式處理。此種方式和“隔離java程序到服務端”有些類似,可以看作把需要保護的代碼和數(shù)據(jù)“隔離”到動態(tài)庫中,不同的是可以在單機程序中運用。缺點和上述“隔離java程序到服務端”類似。7. 不脫離JRE的綜合方式保護特點:非提前編譯,不脫離JRE,采用多種軟保護方式,從多方面防止java程序被竊取。此種方式由于采取了多種保護措施,比如自定義執(zhí)行器和裝載器、加密、JNI、安全性檢測、生成可執(zhí)行文件等等,使保護力度大大增強,同樣能夠非常有效地保護java代碼。缺點:由于jar文件存在方式的改變和java運用中的復雜性,并非java程序中的所有jar都能得到完全的保護;很有可能并不支持所有的JRE版本。 JXMaker屬于此類工具。8. 用加密鎖硬件保護特點:使用與硬件相關的專用程序將java虛擬機啟動程序加殼,將虛擬機配套文件和java程序加密,啟動的是加殼程序,由加殼程序建立一個與硬件相關的 受保護的運行環(huán)境,為了加強安全性可以和加密鎖內植入的程序互動。此種方式與以上“不脫離JRE的綜合方式保護”相似,只是使用了專用硬件設備,也能很好地保護java代碼。缺點:有人認為加密鎖用戶使用上不太方便,且每個安裝需要附帶一個。從以上描述中我們可以看出:1. 各種保護方式都有其優(yōu)缺點,應根據(jù)實際選用2. 要更好地保護java代碼應該使用綜合的保護措施3. 單機環(huán)境中要真正有效保護java代碼,必須要有本地代碼程序配合當然,安全都是相對的,一方面看你的保護措施和使用的工具能達到的程度,一方面看黑客的意愿和能力,不能只從技術上保護知識產權??傊?,在java 代碼保護方面可以采取各種可能的方式,不可拘泥于那些條條框框。
眾所周知,要保護一個頁面,最基礎的就是要屏蔽右鍵。而現(xiàn)在網頁上用得最多的是function click(),即下面這段代碼:
〈script〉
function click(){
if(event.button==2){
alert( ’本網站歡迎您 !!’);
}
}
document.onmousedown=click
〈/script〉
但是這種屏蔽方法的破解方法也是眾所周知的。那就是連續(xù)單擊鼠標左鍵和右鍵便又可以看到右鍵菜單了。但是,我見過一種很好的屏蔽右鍵的方法。它的原理和上面所說的不同。它并不是用JS來編寫的腳本,而是利用定義網頁屬性來起到限制的作用。而且,在屏蔽中應該盡量的避開使用JS腳本。因為只要瀏覽者把IE里的java script腳本禁用了。那么一切屏蔽都白費。
那么繼續(xù)說那種通過修改網頁屬性的屏蔽右鍵的方法。這種方法利用了HTML里的〈body〉來作修改,它只有以下短短的一行代碼:
〈body oncontextmenu=self.event.returnvalue=false〉
這里,定義了oncontextmenu。使得右鍵的值為false,起到了屏蔽右鍵的效果?,F(xiàn)在,再試試看剛才的破解方法,已經不行了。左右鍵連擊已經不能再打開右鍵菜單。不但是這個,再試試看其他的方法。無論你怎樣的亂點,右鍵都沒有用。因為在這個網頁里,右鍵已經不存在了。對于一個不存在的功能鍵,你又能做什么呢?
但是,屏蔽了右鍵還不能解決問題。如果我要復制一段文字,或是一張圖片。那么,把它選中后用ctrl+C 再用 ctrl+V不就可以復制粘貼了嘛。對了,接下來要講的,就是屏蔽左鍵(什么?屏蔽左鍵?那這個網頁不就差不多廢掉了?別急,沒說完呢,左鍵只有一項功能是很討厭的)的選定功能。
那么,如上所說,用JS來屏蔽是沒有用的,治標不治本的。那么,我們就還用網頁的最基礎的語言:HTML來定義吧。還是老招數(shù),定義〈body〉。這次用的參數(shù)是:onselectstart。就是左鍵選定的參數(shù)。代碼如下:
〈body onselectstart="return false"〉
這樣,左鍵選定功能就給輕易屏蔽了。原理和上面的一樣?,F(xiàn)在,再用你的左鍵選擇任意內容把,已經沒有用了。自然也不能ctrl + C,ctrl +V了。那么,現(xiàn)在我們來把這兩部分合并起來。徹底控制左右鍵?。?/p>
〈body oncontextmenu=self.event.returnvalue=false onselectstart="return
false"〉
現(xiàn)在,左右鍵的問題總算是解決了吧。
好,現(xiàn)在我們來看另一個問題。大家都知道,在IE瀏覽器的菜單欄里的“查看”項里。有一個“查看源代碼”選項。這么一來,雖然我們屏蔽了右鍵里的查看源代碼。但是,只要用菜單欄里的查看源代碼,還是可以看到源代碼的。這可怎么辦呢?
我最初的想法是用框架來避開源代碼的查看。也就是說,只要一個網頁是嵌在框架里的,那么在菜單欄里選擇查看源代碼查看到的只是框架網頁的源代碼。一般格式如下:
〈html〉
〈head〉
〈meta HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=gb2312"〉
〈title〉本網站標題〈/title〉
〈/head〉
〈frameset rows="47,*" framespacing="0" border="0"
frameborder="0"〉
〈frame name="header" scrolling="no" noresize target="main"
src="top.htm"〉
〈frame name="main" src="main.htm" scrolling="auto"
target="_self"〉
〈noframes〉
〈body〉
〈p〉此網頁使用了框架,但您的瀏覽器不支持框架。〈/p〉
〈/body〉
〈/noframes〉
〈/frameset〉
〈/html〉
這樣看起來對方是沒有直接看到你的源代碼了。但是,如果一個人要看你的源代碼,那他八成是能看懂的。如果懂一點HTML的話,都能看出這兩句是什么意思:
〈frame name="header" scrolling="no" noresize target="main"
src="top.htm"〉
〈frame name="main" src="main.htm" scrolling="auto"
target="_self"〉
這兩句的意思就是:在header(也就是網頁頂部)處引用相對路徑下的top.htm網頁文件。而在main(也就是占據(jù)網頁大部分頁面的位置)處引用相對路徑下的main.htm網頁文件。就這兩點是關鍵的,其他就不作解釋了,大家也都懂的。而上面所講的利用框架來隱藏源代碼的方法就是將要顯示頁面放在main部分。而將header部分的大小設為0。但是這樣一來,利用菜單欄里的查看源代碼,還是能查看到框架網頁的源代碼。只要看到這兩句,就知道我們前面用的手法了。也就是說,只要將框架網頁的名字改為目標網頁,便可以用相同的方法直接看到目標網頁的源代碼了。如:框架網頁:的源代碼如上,就可以改為。這樣便可直接瀏覽被保護網頁,屏蔽源代碼的效果還是沒有達到。
得到的永遠比失去的多!
2006-4-15 18:55 #1
UID 29169
會員 狒狒
用戶組 版主 [查看詳情]
性別 : 男
閱讀權限 : 16
來自 : 湖北 武漢
狀態(tài)
帖子 555 [查看詳情]
精華 3
主題 96
回復 459
積分策略 積分 : 607
現(xiàn)金 1166 MMB 存款 1000 MMB
星級
失蹤 0 天 [查看詳情]
注冊 51 天
注冊 2006-3-9
| 今日免費申請會員!
--------------------------------------------------------------------------------
那么,有些人就會想到,如果對方看不到框架網頁的源代碼。又何談去直接打開被保護網頁?對,這就是接下來我要講的。如果要一個頁面的菜單欄內的查看源代碼失去效用。那最簡單的辦法就是去掉菜單欄。而這一點是可以通過彈出窗口來實現(xiàn)的。之所以不選用超鏈接打開無菜單欄窗口是因為那樣會暴露目標地址,瀏覽者可以直接在瀏覽器中敲入地址,而繞過這個屏蔽的菜單欄。要使用超鏈接打開無菜單欄窗口,就必須在一個已受到源代碼屏蔽保障的網頁中使用相關鏈接。
那么,我們就看看如何利用彈出窗口來去掉菜單欄。其實,我們要做的,就是讓目標網頁在一個廣告條中打開。這個代碼幾乎每個大型網站都會有的。代碼如下:
〈script〉
〈!--
window.open("red.htm", "red", "resizable=yes,width=500,height=300");
--〉
〈/script〉
這里,在window.open后的括號里的第一個參數(shù)就是彈出窗口所顯示的網頁的位置,這里例子里是先對位置下的red.htm網頁文件。這時運行便會談出一個顯示有red.htm的無菜單欄的窗口。好,我們的目的達到了。但是,這個窗口有一個缺陷,就是沒有滾動條。因為在談出窗口的語句:window.open里并沒有關于滾動條的參數(shù),(或是我不知道?歡迎高手來信指出),所以這里打開的網頁建議只做成網頁的導航頁。
但是,用以上方法取消菜單欄,必須有一個第二方的網頁來作彈出的工作。那么,這個用來彈出窗口的網頁又成為了一個問題的所在。舉例來說:假設,我們用一個index.htm來作彈出窗口的工作。也就是打開index.htm之后,會彈出red.htm的無菜單欄窗口。前面我們也提到了,如果知道了一個網頁的地址后,無論這個網頁是否隱藏在無菜單欄之下,你都能看到它的源代碼。那么,不讓這個red.htm的地址暴露也就成了解決這個問題的關鍵。但是,只要這個index.htm被打開,就可以看到源代碼。但是,不妨反過來想想,如果我們把index.htm給關起來呢?只要在瀏覽者沒有來得及查看index.htm之前將它關閉,就能保住它的源代碼了。那么,在這個index.htm里就有得做些文章了。
那就是,添加關閉網頁的代碼。
那么,我們就可以用window.close來關閉窗口。代碼如下:
〈script〉
〈!--
window.open();
--〉
〈/script〉
那么,現(xiàn)在我們把兩部分代碼合并起來?,F(xiàn)在,得到的效果就是——直接有一個無菜單欄的窗口打開了。因為計算機的處理速度很快,如果我們將這兩段代碼緊接著寫在一起,那么我們就只能看到新建的窗口。代碼如下:
〈script〉
〈!--
window.open("red.htm", "red", "resizable=yes,width=500,height=300");
window.close();
--〉
〈/script〉
而原來的窗口,已在我們無察覺的情況下關閉了。這樣,就別說查看該網頁的源代碼了。這里,加入上面源代碼的網頁起了一個跳板的作用。但是,在這里,我們要注意幾點。第一,用來做跳板的網頁不應該命名為index.htm。將它換一個名字,然后把默認首頁的名字改為更改過的名字。這樣,是瀏覽者能在輸入網之后便自動訪問該頁。而又不致讓對方知道該頁的名稱。如果不這樣做,就會導致對方猜測出該頁的位置。如:172.0.0.0/index.htm。這樣,就可以通過在瀏覽器中提交:View-Source:就可以看到該頁的源代碼了。
在屏蔽掉了菜單欄和工具欄之后,我們想,如果沒有了最上方的窗口條該多好呢?下面我們要做的事情,有前提,就是在上面所說的在利用跳板頁面打開一個無菜單欄的窗口之后。我們要做什么呢?就是讓我們顯示網站內容的窗口只顯示內容,(是啊,網站不就是給別人瀏覽的嗎?要瀏覽器和windows的那么多功能做什么呀……)只要內容,其余一律去掉。我們就可以通過一段java
script來完成。下面這段代碼就是用來定義無任何窗口特征的代碼:
〈script〉
function open1(url){
newwin=window.open(url,’newwindow’,’fullscreen=1’)
newwin.resizeTo(800,600)
newwin.moveTo(screen.width/0-800,screen.height/0-600)
}
〈/script〉
其中,function open1(url)定義了超鏈接的寫法。所以,我們在寫鏈接的地址時,應該這樣寫:java script:open1(url)。比如我要打開一個無窗口特征的新浪首頁就應該在文字或圖片的超鏈接里這樣寫:java
script:open1(‘http:’)。當然,括號內也支持相對路徑。最后寫出來的格式應該是:
〈script〉
function open1(url){
newwin=window.open(url,’newwindow’,’fullscreen=1’)
newwin.resizeTo(800,600)
newwin.moveTo(screen.width/0-800,screen.height/0-600)
}
〈/script〉
〈body oncontextmenu=self.event.returnvalue=false onselectstart="return
false"〉
〈td width="100%"〉〈a href="java script:open1(’main.htm’),window.close()"〉〈img
border="0" src="pic/blank1.gif" style="position: absolute;
left: 556; top: 142" width="169" height="57"〉〈/a〉〈/td〉
〈/body〉
這樣,我們就達到了打開無窗口邊的網頁了。并且,在這個網頁中,會自動加入滾動條,這樣,就不會像前面那樣看不到下面的內容啦。
最后我們要做的工作,就是把每一頁,或者你認為重要的關鍵的頁面進行加密,就OK啦。怎樣對網頁的源代碼進行加密就不用我多說了吧?網上到處都有,可以用工具,也可以自己寫一個htm文件來轉換。加密軟件,我推薦“Batch
HTML Encryptor”,去google找吧。還有轉換加密網頁的代碼如下:
〈HTML〉〈HEAD〉〈TITLE〉網頁加密解密〈/TITLE〉
〈META http-equiv=Content-Type content="text/html; charset=gb2312"〉
〈META content="MSHTML 6.00.2600.0" name=GENERATOR〉〈!-- 大地軟件工作室--〉〈LINK
href="style.css" rel=stylesheet〉
〈META content="Microsoft FrontPage 4.0" name=GENERATOR〉
〈/HEAD〉
〈BODY bgColor=#ffffff leftMargin=0 topMargin=0 onload=initStyleElements()〉
〈DIV
style="LEFT: 139px; WIDTH: 106px; POSITION: absolute; TOP: 52px; HEIGHT:
36px"〉
〈TABLE cellSpacing=0 cellPadding=0 width=760 align=center border=0〉〈!--DWLayoutTable--〉
〈TBODY〉
〈TR〉
〈TD vAlign=top align=middle width=760 height=310〉
〈DIV align=center〉
〈H2〉
〈SCRIPT language=java script〉
〈!--
var i=0;
var ie=(document.all)?1:0;
var ns=(document.layers)?1:0;
function initStyleElements() /* Styles for Buttons Init */
{
var c = document.pad;
if (ie)
{
//c.text.style.backgroundColor="#DDDDDD";
c.compileIt.style.backgroundColor="#C0C0A8";
c.compileIt.style.cursor="hand";
c.select.style.backgroundColor="#C0C0A8";
c.select.style.cursor="hand";
c.view.style.backgroundColor="#C0C0A8";
c.view.style.cursor="hand";
c.retur.style.backgroundColor="#C0C0A8";
c.retur.style.cursor="hand";
c.clear.style.backgroundColor="#C0C0A8";
c.clear.style.cursor="hand";
}
else return;
}
/* Buttons Enlightment of "Compilation" panel */
function LightOn(what)
{
if (ie) what.style.backgroundColor = ’#E0E0D0’;
else return;
}
function FocusOn(what)
{
if (ie) what.style.backgroundColor = ’#EBEBEB’;
else return;
}
function LightOut(what)
{
if (ie) what.style.backgroundColor = ’#C0C0A8’;
else return;
}
function FocusOff(what)
{
if (ie) what.style.backgroundColor = ’#DDDDDD’;
else return;
}
/* Buttons Enlightment of "Compilation" panel */
function generate() /* Generation of "Compilation" */
{
code = document.pad.text.value;
if (code)
{
document.pad.text.value=’Compiling...Please wait!’;
setTimeout("compile()",1000);
}
else alert(’First enter something to compile and then press CompileIt’)
}
function compile() /* The "Compilation" */
{
document.pad.text.value=’’;
compilation=escape(code);
document.pad.text.value="〈script〉\n〈!--\ndocument.write(unescape(\""+compilation+"\"));\n//--〉\n〈\/script〉";
i++;
if (i=1) alert("Page compiled 1 time!");
else alert("Page compiled "+i+" times!");
}
function selectCode() /* Selecting "Compilation" for Copying */
{
if(document.pad.text.value.length〉0)
{
document.pad.text.focus();
document.pad.text.select();
}
else alert(’Nothing for be selected!’)
}
function preview() /* Preview for the "Compilation" */
{
if(document.pad.text.value.length〉0)
{
pr=window.open("","Preview","scrollbars=1,menubar=1,status=1,width=700,height=320,left=50,top=110");
pr.document.write(document.pad.text.value);
}
else alert(’Nothing for be previewed!’)
}
function uncompile() /* Decompiling a "Compilation" */
{
if (document.pad.text.value.length〉0)
{
source=unescape(document.pad.text.value);
document.pad.text.value=""+source+"";
}
else alert(’You need compiled code to uncompile it!’)
}
// --〉
〈/SCRIPT〉
〈BR〉〈B〉〈FONT color=#333333〉網頁HTML源代碼加密解密器〈/FONT〉〈/B〉〈/H2〉〈/DIV〉
〈TABLE cellSpacing=0 borderColorDark=#000000 cellPadding=10 width=750
align=center borderColorLight=#ffffff border=2〉
〈TBODY〉
〈TR〉
〈TD〉
〈DIV align=center〉〈BR〉將你的源代碼貼到編輯區(qū)域即可〈BR〉〈BR〉
〈TABLE cellSpacing=0 cellPadding=0 width="100%" border=0〉
〈TBODY〉
〈TR〉
〈TD width="100%"〉〈!-- Compilation Panel --〉
〈FORM name=pad method=post align="center"〉
〈DIV align=center〉〈TEXTAREA style="WIDTH: 95%; BACKGROUND-COLOR: #ebebeb"
name=text rows=11 cols=58〉〈/TEXTAREA〉
〈BR〉〈BR〉〈BR〉〈INPUT onmouseover=LightOn(this) onclick=generate() onmouseout=LightOut(this)
type=button value=加密 name=compileIt〉
〈INPUT onmouseover=LightOn(this) onclick=selectCode() onmouseout=LightOut(this)
type=button value=全選 name=select〉
〈INPUT onmouseover=LightOn(this) onclick=preview() onmouseout=LightOut(this)
type=button value=預覽 name=view〉
〈INPUT onmouseover=LightOn(this) onclick=uncompile() onmouseout=LightOut(this)
type=button value=解密 name=retur〉
〈INPUT onmouseover=LightOn(this) onmouseout=LightOut(this) type=reset value=清除
name=clear〉
〈/DIV〉〈/FORM〉〈!-- Compilation Panel --〉〈/TD〉〈/TR〉〈/TBODY〉〈/TABLE〉〈/DIV〉〈/TD〉〈/TR〉〈/TBODY〉〈/TABLE〉
〈DIV align=center〉〈BR〉〈/DIV〉
〈DIV align=center〉〈/DIV〉 〈/TD〉〈/TR〉〈/TBODY〉〈/TABLE〉
〈/DIV〉
〈DIV〉〈/DIV〉〈/BODY〉〈/HTML〉
總結一下……按我的思路,屏蔽網頁源代碼主要分為以下幾個步驟:
1. 做一個網頁跳板,彈出要保護的廣告條狀頁面,并將自身關閉,以避免泄露需保護網頁的地址。
2. 由于上述條件屏蔽了廣告條內網頁的源代碼,所以可以用這個網頁作為歡迎頁。
3. 在歡迎頁中,利用java script以超連接的形式來打開無窗口邊的新窗口顯示網站內容。
4. 對每一個頁面或者對重要的關鍵的頁面進行源代碼加密,為源代碼加一把鎖。(有些人說對源代碼進行加密沒有用,但是我覺得要使用另類點的加密方法就可以了,比如軟件的加密方法就很普通。但是用我自己寫的htm文件加密的源代碼,一般軟件是不能進行解密的。大家有興趣的話可以試試。)
5. 最后不得不提的就是windows網頁臨時文件夾了,那里面會把源代碼紀錄的。但是不用怕,加入一種代碼,就可以使windows不下載網頁的源代碼,直接瀏覽??梢匀フ艺摇?/p>
有些東西要注意的:
1. 在文中所說的自動關閉網頁的語句:window.close()有一個弊病。就是會在關閉窗口之前詢問是否關閉窗口,如果選擇否的話目的還是達不到。
2. 以上一切都只對IE瀏覽器有效用,如果用別的瀏覽器來瀏覽,就有可能出現(xiàn)屏蔽不成功的現(xiàn)象。
3. 關于網頁源代碼屏蔽,一直以來是可望而不可及的。我只是把思路寫下來,具體實現(xiàn),還是要靠大家自己研究的啦。
首先,你看到的源代碼不可能是java代碼,java代碼是服務器端代碼,在編譯成頁面以后你是看不到的。你可以看到的只是javascript代碼。
其實一個頁面不用html標簽,使用javascript也能寫可以寫。因為頁面上的標簽其實也是一個對象。Javascript通過面想對象的方法處理頁面。邏輯全部都是在后臺通過java代碼處理的。返回到前臺的只有顯示的結果,Javascript所要做的之后把得到的結果顯示出來而已。
我寫一小段代碼,你看看是不是這個意思。
body/body
script language="javascript"
var newtable,newtr,newtd;
newtable = document.createElement("table");
newtable.border = 1;
document.body.appendChild(newtable);
newtr = newtable.insertRow();
newtd = document.createElement("td");
newtd.innerText="Name";
newtr.appendChild(newtd);
newtd = document.createElement("td");
newtd.innerText="Sex";
newtr.appendChild(newtd);
newtd = document.createElement("td");
newtd.innerText="Age";
newtr.appendChild(newtd);
newtr = newtable.insertRow();
newtd = document.createElement("td");
newtd.innerText="Jack";
newtr.appendChild(newtd);
newtd = document.createElement("td");
newtd.innerText="F";
newtr.appendChild(newtd);
newtd = document.createElement("td");
newtd.innerText="22";
newtr.appendChild(newtd);
/script
這段代碼是在頁面上畫一個表格,表格里有兩行,相當于
table
tr
tdName/tdtdSex/tdtdAge/td
tr
tr
tdJack/tdtdF/tdtd22/td
tr
/table
如果是web程序就發(fā)布,自然看不到
如果是應用程序,打成exe就OK了
網站標題:屏蔽源代碼中java html屏蔽代碼
分享鏈接:http://jinyejixie.com/article6/dossjig.html
成都網站建設公司_創(chuàng)新互聯(lián),為您提供微信小程序、動態(tài)網站、響應式網站、虛擬主機、網站設計公司、全網營銷推廣
聲明:本網站發(fā)布的內容(圖片、視頻和文字)以用戶投稿、用戶轉載內容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內容未經允許不得轉載,或轉載時需注明來源: 創(chuàng)新互聯(lián)