【问题标题】:Verifying Jar Signature验证 Jar 签名
【发布时间】:2011-08-01 01:17:33
【问题描述】:

我正在尝试以编程方式验证 jar 文件是否未被明显篡改。我有 2 个要防止的用例。 1) 现有类的修改 2) jar 中新增类

我使用 jarsigner 对 jar 进行了签名。当我使用 jarsigner 验证上述任何一种情况时,它的工作方式与我预期的一样。

当我尝试使用示例以编程方式执行此操作时 How to verify a jar signed with jarsigner programmatically 要么 How to verify signature on self signed jar? 但是,我没有得到任何 SecurityExceptions ......或任何异常。

不确定我做错了什么,因为这些 sn-ps 似乎对其他人有用。有任何想法吗?这是 JDK 1.6 顺便说一句。

编辑: 按照下面的要求,代码示例...提供您自己修改过的 jar :)

    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);
            }
    }
}

【问题讨论】:

  • 你是如何篡改被测 JAR 的?
  • 我用 7zip 打开它。我添加了一个新的包目录,里面有一些类文件,并用重新编译的版本修改了一些现有的类文件。
  • 如果 jarsigner 拒绝更改后的 JAR,但您的代码接受它,sscce 可能有助于发现问题。

标签: java jar-signing


【解决方案1】:

使用下面的示例,我获得了正确签名的 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改编的循环。

【讨论】:

  • 嗯。您的示例与我的几乎相同,但您会遇到安全异常,而我没有。您使用的是什么确切的 JDK?
  • 版本无关。 SecurityException 仅在条目签名不正确时才被抛出。也可以通过篡改META-INF/&lt;alias&gt;.SF来触发。
  • 我将把它标记为答案,因为它显然适用于大多数人。当我有机会时,我将用一个更简单的例子来尝试它......如果我弄清楚为什么它对我不起作用但不知道如何解决它,我想我会提出一个新问题。
  • @Petesh:在 jdk8 中可以看到类似的符号 here
  • 值得注意的是,如果没有策略管理器坚持对所有 JAR 进行签名,如果 JAR 根本没有签名,此方法将返回 true ;-)
【解决方案2】:

我明白为什么这会发生在我身上……这是一个愚蠢的错误。

我有我的篡改签名 jar,但我也编译了所有相同的类,因为这是我的开发环境。所以类加载器在 jar 类上选择了编译的类。编译后的类没有清单,因此没有产生安全错误。

一旦我删除了我编译的类,我就会得到预期的安全异常。

【讨论】:

    猜你喜欢
    • 2012-05-05
    • 2019-09-07
    • 2013-03-15
    • 2011-06-25
    • 2015-06-28
    • 2010-10-25
    • 1970-01-01
    • 2014-01-18
    • 2013-05-10
    相关资源
    最近更新 更多