【问题标题】:How do I unsign a jar?如何取消对 jar 的签名?
【发布时间】:2011-10-13 16:09:20
【问题描述】:

有没有办法取消对 java jar 文件的签名?我有一些已签名的 jar 尝试在我的开发环境中使用,但我遇到了安全异常,因此我想取消对这些 jar 的签名,并且可以在以后准备部署时对其进行签名。

【问题讨论】:

  • 你检查了例如这个:chemaxon.com/forum/ftopic65.html?
  • 有问题的罐子是从哪里来的?为什么你不能登录你的开发环境?
  • 显然有办法。 ;-) 但是,为什么不在开发过程中避免签署 JAR 呢?如果你是 JAR 的控制者,这应该在你的权力范围内;如果您不是 JAR 的控制者,那么您可能不打算篡改它(或者原始开发人员不会签署它)。
  • 是的,这些罐子是我的或来自 Maven 和其他来源的未签名罐子。我已经修改了我的构建系统,所以不清楚这是否仍然是一个问题......我当然在一年多的时间里没有遇到过这样做的需要。

标签: java jar jar-signing


【解决方案1】:

我不知道答案,但我会这样做:

  1. 解压缩 jar 文件或有问题的文件(jar 只是 zip)
  2. 在 META-INF 目录中查找不是 MANIFEST-MF 的内容。
  3. 删除那些东西。
  4. 打开 MANIFEST-MF 并删除看起来与签名相关的内容。
  5. 重新打开。

【讨论】:

  • 这就是你所做的。
  • 这就是我必须做的,我从来没有找到一种方法来删除签名而不解压缩。但是,我想,如果这个答案对步骤 2、3、4 更具体,因为有时除了 MANIFEST-MF 之外还有一些其他的东西是必需的,而不是与签名相关的。喜欢 APPLICATION.JNLP!
  • 对于googlers,Netbeans说:“没有在库中添加安全属性”,“库已经签名”,所以取消签名并签名,这个答案解决了问题!
  • 我在此线程中发布了一个答案,其中包含为您执行此操作的源代码。希望能帮助到你。干杯
  • 如果您查看 jarsigner 工具及其作用,它会生成 3 样东西:1) .SF 文件(签名文件),2) 基于所使用算法的签名块文件(例如 . RSA、.DSA 等)3)修改或创建 MANIFEST.MF 文件因此,如果您删除 META-INF 目录中的所有内容,则可能会删除可能需要的 jar 的其他资源(即属性文件)等)见这里:docs.oracle.com/javase/8/docs/technotes/tools/windows/…docs.oracle.com/javase/tutorial/deployment/jar/intro.html
【解决方案2】:

要从 jar 文件中删除签名,请从中删除 META-INF 目录。 jar 文件是一个 zip 文件,因此在 Linux 上您可以这样做:

zip -d file.jar 'META-INF/*.SF' 'META-INF/*.RSA'

如果您有许多 jar 文件要取消签名,以下命令对当前目录及以下目录中的每个 jar 文件执行此操作:

find . -name '*.jar' -exec zip -d '{}' 'META-INF/*.SF' 'META-INF/*.RSA' ';'

【讨论】:

  • 我认为您还必须编辑META-INF/MANIFEST.MF 不是吗?或者您可以将签名保留在该文件中并让 jar 仍以未签名的方式工作吗?
  • 删除文件似乎没有问题。
  • 感谢您的检查,我投了赞成票。我还没有为自己验证这一点,并且仍然怀疑它是否适用于所有情况。我希望您不要介意我的怀疑:-) 该解决方案很好,如果它适用于我的情况,它将是对我的问题的更令人满意的答案......每当我再次遇到这个问题时,我都会对其进行测试并更新这个答案。
  • 这两个命令都适用于我的构建文件引用的所有 3rd 方 jar。我用-not -path 调整了find 命令以排除某些目录。
  • 此解决方案不起作用。删除META-INF/MANIFEST.MF中的签名信息很重要
【解决方案3】:

我看到一个答案已被接受,但我认为这无论如何可能有用:

我已经制作了一些东西(部分来自其他帖子)来自动化任务。
没有任何保修,但它适用于我:)
复制 Jar 文件,同时删除签名信息。
注意,MANIFEST 只剩下 MAIN 部分!

使用javac JarUnsigner.java 创建 .class 文件
使用java -cp <class dir> JarUnsigner <inJar> <outJar>

import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Enumeration;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipOutputStream;

public class JarUnsigner {
  
  private static final String MANIFEST = "META-INF/MANIFEST.MF";
  
  public static void main(String[] args){

    if (args.length!=2){
      System.out.println("Arguments: <infile.jar> <outfile.jar>");
      System.exit(1);
    }
    String infile = args[0];
    String outfile = args[1];
    if ((new File(outfile)).exists()){
      System.out.println("Output file already exists:" + outfile);
      System.exit(1);
    }
    try{
      ZipFile zipFile = new ZipFile(infile);
      final ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(outfile));
      for (Enumeration e = zipFile.entries(); e.hasMoreElements();) {
        ZipEntry entryIn = (ZipEntry) e.nextElement();

        if (! exclude_file( entryIn.getName() ) ) {

          /* copy the entry as-is */
          zos.putNextEntry( new ZipEntry( entryIn.getName() ));
          InputStream is = zipFile.getInputStream(entryIn);
          byte[] buf = new byte[1024];
          int len;
          while ((len = (is.read(buf))) > 0) {
            zos.write(buf, 0, len);
          }
          zos.closeEntry();

        } else {

          if (MANIFEST.equals(entryIn.getName())){
            /* if MANIFEST, adjust the entry */
            zos.putNextEntry(new ZipEntry(MANIFEST));

            // manifest entries until first empty line. i.e. the 'MainAttributes' section
            // (this method is used so to keep the formatting exactly the same)
            InputStream mIS = zipFile.getInputStream(entryIn);
            BufferedReader in = new BufferedReader(new InputStreamReader(mIS));
            String line = in.readLine();
            byte[] mNL = "\n".getBytes("UTF-8");
            while( line != null && !line.trim().isEmpty() ) {
              zos.write( line.getBytes("UTF-8"));
              zos.write( mNL );
              line = in.readLine();
            }
            zos.write( mNL );
            zos.closeEntry();

          }else{
            /* else: Leave out the Signature files */
          }

        }

      }
      zos.close();
      System.out.println("Successfully unsigned " + outfile);
      
    }catch(IOException ex){
      System.err.println("Error for file: " + infile);
      ex.printStackTrace();
      System.exit(1);
    }
  }

  /**
   * Exclude .SF signature file
   * Exclude .RSA and DSA (signed version of .SF file) 
   * Exclude SIG-  files  (unknown sign types for signed .SF file)
   * Exclude Manifest file
   * @param filename
   * @return 
   */
  public static boolean exclude_file(String filename){
    return filename.equals("META-INF/MANIFEST.MF") ||
           filename.startsWith("META-INF/SIG-") || 
           filename.startsWith("META-INF/") && ( filename.endsWith(".SF") || filename.endsWith(".RSA") || filename.endsWith(".DSA") );
  }
  
}

在 ANT 中使用如下方式为一堆 jar 取消签名:

<apply executable="java" dest="${output-dir}"> 
    <arg value="-cp" />
    <arg value="${dev-dir}" />
    <arg value="JarUnsigner" />
    <srcfile/> 
    <targetfile/>
    <fileset dir="${input-dir}" includes="*.jar"/> 
    <mapper type="glob" from="*.jar" to="*.jar"/> <!-- uses "dest"-->
</apply>

【讨论】:

  • 好主意!我还没有测试它,但我赞成引起一些注意,看看其他人是否有时间测试这个解决方案。这正是我想要的。
  • 谢谢。我们已经使用了很长一段时间了。效果很好
【解决方案4】:

我通过小修改成功验证了 DwB 的答案:正如Is there a quick way to delete a file from a Jar / war without having to extract the jar and recreate it? 所说,仅从 jar 工具中删除是不可能的。我只需要在专有构建脚本中做一点小改动,而且我不想重新封装整个 jar。

当我只将重要的 .RSA 文件设为零大小时,我意识到 unsign 是可能的。这只能通过jar u 命令来完成:

cd %JAR_DIR%
jar xvf myapp.jar META-INF/MYAPP.RSA
type nul > META-INF/MYAPP.RSA
jar uvf myapp.jar META-INF/MYAPP.RSA
rmdir /S/Q META-INF

【讨论】:

  • 我没有时间测试这个解决方案,但它看起来不错。
  • 从 jarsigner 工具文档中,它执行以下操作:1) .SF 文件(签名文件)2)基于所使用算法的签名块文件(例如 .RSA、.DSA 等)3 ) 修改(或创建,如果它尚不存在) MANIFEST.MF 文件摘要:只需删除前 2 个文件并删除 MANIFEST.MF 文件,或打开它并删除为每个文件列出的所有哈希列在那里)。否则,您将删除其他需要的文件(即属性文件等)。参考文献:docs.oracle.com/javase/8/docs/technotes/tools/windows/…
【解决方案5】:

如果您查看 jarsigner 工具及其作用,它会生成 3 件事: 1) .SF 文件(签名文件) 2) 基于所使用算法的签名块文件(例如 .RSA、.DSA 等) 3) 修改或创建 MANIFEST.MF 文件

总结: 要“取消签名 jar”,只需删除前 2 个文件(.sf 和 .dsa/rsa 文件)。 要么删除 MANIFEST.MF 文件,要么打开它并删除为每个 .class 和其他文件列出的所有哈希值。

因此,如果您删除 META-INF 目录中的所有内容,则可能会删除可能需要的 jar 的其他资源(即属性文件等)。这种删除“看起来与签名相关”的所有内容的“猎枪方法”是有害的,并且不遵循以下原则:第一不伤害(对您的 .jar)。

请看这里: https://docs.oracle.com/javase/8/docs/technotes/tools/windows/jarsigner.html

https://docs.oracle.com/javase/tutorial/deployment/jar/intro.html

了解签名和验证

"...当您签署 JAR 文件时,您的公钥与相关证书一起被放入存档中,以便任何想要验证您的签名的人都可以轻松使用它...。 摘要和签名文件

当您签署 JAR 文件时,档案中的每个文件都会在档案的清单中获得一个摘要条目。以下是此类条目的示例:

名称:test/classes/ClassOne.class SHA1-摘要:TD1GZt8G11dXY2p4olSZPc5Rj64=

签名 JAR 文件时,会自动生成一个签名文件并将其放置在 JAR 文件的 META-INF 目录中,该目录与包含存档清单的目录相同。签名文件的文件名带有 .SF 扩展名。

签名块文件

除了签名文件之外,在对JAR文件进行签名时,会自动在META-INF目录下放置一个签名块文件。与清单文件或签名文件不同,签名块文件不是人类可读的。

签名块文件包含两个验证必不可少的元素:

使用签名者的私钥生成的 JAR 文件的数字签名 包含签名者公钥的证书,供任何想要验证签名 JAR 文件的人使用 签名块文件名通常具有 .DSA 扩展名,表明它们是由默认数字签名算法创建的。如果与其他标准算法相关的密钥用于签名,其他文件扩展名也是可能的。

【讨论】:

    【解决方案6】:

    如果 jars 是由您开发的,那么它们是可以信任的,您可能不需要对它们签名。但是,如果您是从外部获取它们,则应在使用它们之前调查安全异常发生的原因。

    【讨论】:

    • 我也在做同样的事情。我作为承包商修改大型应用程序的小部分,他们的构建服务器会自动签名。我需要在提供的 jar 中开发和覆盖类以进行测试。他们珍视证书(这是一家银行),所以我必须按照他们的条件处理他们构建的输出。
    • 这些 jars 是我正在开发的,在部署之前我不需要签署它们...但偶尔我想在我的开发环境中使用生产 jars 或使用已经我将要部署的签名 jar。在这种情况下,解压缩所有 jar 文件,删除签名并重新压缩是很痛苦的。我已经重新设计了我的构建系统,所以这不再经常出现了。我的构建系统现在将未签名的 jar 和签名的 jar 保存在构建目录中,以便我可以在闲暇时在它们之间切换。
    【解决方案7】:

    另一个变体,它也编辑 MANIFEST.MF,即从第一个空行中删除所有内容(根据您的情况编辑“jarlocation”和“signer”部分):

    Tmpdir=tmp.$$
    mkdir -p "$Tmpdir"
    cd "$Tmpdir"
    for i in <jarlocation>/*.jar; do \
        printf 'Doing %s\n' "$i"
        unzip "$i" 'META-INF/*'
        sed -i '/^[[:space:]]*$/,$d' META-INF/MANIFEST.MF
        zip -r "$i" META-INF/MANIFEST.MF
        test -f META-INF/<signer>.SF && zip -d "$i" 'META-INF/<signer>.*'
        rm -rf META-INF
    done
    cd ..
    rm -rf "$Tmpdir"
    printf 'Unsigning finished\n'
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-11-02
      • 2011-06-25
      • 2012-05-05
      • 2011-03-30
      • 1970-01-01
      • 2017-02-07
      • 2015-12-22
      • 1970-01-01
      相关资源
      最近更新 更多