2011-04-07 143 views
6

我試圖以編程方式驗證一個jar文件沒有被明顯篡改。我有兩個我想防止的用例。 1)現有類別的修改 2)在罐子中添加新類別驗證Jar簽名

我使用jarsigner在jar中籤名。當我使用jarsigner驗證上述任何一種情況時,它的工作方式與我所期望的相同。

當我嘗試這樣做編程方式使用樣本然而 How to verify a jar signed with jarsigner programmaticallyHow to verify signature on self signed jar? ,我完全不爲此事得到任何SecurityExceptions ......或任何異常。

不知道我在做什麼錯,因爲這些片段似乎適用於其他人。有任何想法嗎?這是JDK 1.6順便說一句。

編輯: 如下要求,代碼樣本...提供自己的改型罐:)

JarFile myJar; 

    try 
    { 
     //Insert the full path to the jar here  
     String libPath = "" 
     stature = new JarFile(libPath,true); 

     //Don't really need this right now but was using it to inspect the SHA1 hashes 

     InputStream is = myJar.getInputStream(myJar.getEntry("META-INF/MANIFEST.MF")); 
     Manifest man = myJar.getManifest();    
     is.close(); 

     verifyJar(myJar); 

    } 
    catch (IOException ioe) 
    { 
     throw new Exception("Cannot load jar file", ioe); 
    } 


private void verifyJar(JarFile jar) throws Exception 
{ 
    Enumeration<java.util.jar.JarEntry> entries = jar.entries(); 
    while (entries.hasMoreElements()) 
    { 
     java.util.jar.JarEntry entry = entries.nextElement(); 

     try 
     { 
      jar.getInputStream(entry); 

      //Also tried actually creating a variable from the stream in case it was discarding it before verification 
      //InputStream is = jar.getInputStream(entry); 
      //is.close(); 
     } 
      catch (SecurityException se) 
      { 
       /* Incorrect signature */      
       throw new Exception("Signature verification failed", se); 
      } 
      catch (IOException ioe) 
      { 
       throw new Exception("Cannot load jar file entry", ioe); 
      } 
    } 
} 

+0

你是如何篡改受測JAR的? – trashgod 2011-04-07 21:49:53

+0

我用7zip打開它。我添加了一個新的包目錄,其中包含一些類文件,並用重新編譯的版本修改了一些現有的類文件。 – Amasuriel 2011-04-07 21:52:26

+0

如果'jarsigner'拒絕了更改後的JAR,但是您的代碼接受它,[sscce](http://sscce.org/)可能有助於發現問題。 – trashgod 2011-04-07 21:56:14

回答

1

我想通了這是爲什麼發生在我身上......這是一個愚蠢的錯誤。

我有我的篡改簽名的jar,但我也有所有相同的類編譯,因爲這是我的開發環境。所以類加載器通過jar類獲取已編譯的類。編譯的類沒有清單,所以沒有產生安全錯誤。

一旦我刪除了我編譯的類,我得到了預期的安全異常。

7

使用下面的例子中,我獲得了預期的結果的正確簽名JAR(true)和改變的JAR(false)。觸發測試效果的一種簡單方法是更改​​META-INF/MANIFEST.MF中列出的摘要之一。

請注意,此方法會忽略清單中列出的而非的條目。使用jarsigner -verify報告,「此jar包含未經過完整性檢查的未簽名條目。」在完全讀取流之後,entry.getCodeSigners()可用於確定條目是否具有任何簽名者。

import java.io.IOException; 
import java.io.InputStream; 
import java.util.Enumeration; 
import java.util.jar.JarEntry; 
import java.util.jar.JarFile; 

/** @see http://stackoverflow.com/questions/5587656 */ 
public class Verify { 

    public static void main(String[] args) throws IOException { 
     System.out.println(verify(new JarFile(args[0]))); 
    } 

    private static boolean verify(JarFile jar) throws IOException { 
     Enumeration<JarEntry> entries = jar.entries(); 
     while (entries.hasMoreElements()) { 
      JarEntry entry = entries.nextElement(); 
      try { 
       byte[] buffer = new byte[8192]; 
       InputStream is = jar.getInputStream(entry); 
       while ((is.read(buffer, 0, buffer.length)) != -1) { 
        // We just read. This will throw a SecurityException 
        // if a signature/digest check fails. 
       } 
      } catch (SecurityException se) { 
       return false; 
      } 
     } 
     return true; 
    } 
} 

注:對於JDK 8,其不足以僅僅獲得輸入流。如在jarsigner中一樣,也必須從中讀取流。在上面的代碼中,在獲取輸入流後添加了一個從jar signersource改編的循環。

+0

嗯。您的示例與我的示例幾乎完全相同,但您會遇到安全性異常,而我則不會。您使用的是什麼確切的JDK? – Amasuriel 2011-04-08 16:22:46

+0

版本無關緊要。僅當條目簽名不正確時才拋出SecurityException。您也可以通過篡改'META-INF/ .SF'來觸發它。 – trashgod 2011-04-08 20:46:23

+0

我打算將其標記爲答案,因爲它對大多數人都很有用。當我有機會的時候,我會用一個更簡單的例子來嘗試它...如果我弄清楚爲什麼它不適合我而不是如何解決它,我想我會打開一個新的問題。 – Amasuriel 2011-04-11 18:12:48