【问题标题】:"Invalid signature file" when attempting to run a .jar尝试运行 .jar 时出现“无效的签名文件”
【发布时间】:2010-11-03 05:23:22
【问题描述】:

我的 java 程序打包在一个 jar 文件中,并使用了一个外部 jar 库,bouncy castle。我的代码编译正常,但是运行 jar 会导致以下错误:

线程“main”java.lang.SecurityException 中的异常:Manifest 主要属性的签名文件摘要无效

我已经用谷歌搜索了一个多小时来寻找解释,但发现的价值很小。如果有人以前看到过这个错误并且可以提供一些帮助,我将不胜感激。

【问题讨论】:

  • 您是否要为自己的 jar 签名?如果是这样,您打算如何签名?
  • 不,至少我不这么认为。 Xcode 可能会尝试自行对其进行签名,但似乎没有任何设置可以关闭它。
  • 不要忘记检查包含已实现接口的 jar 是否也被签名!

标签: java jar executable-jar


【解决方案1】:

对于那些在尝试使用maven-shade-plugin 创建阴影uber-jar 时遇到此错误的用户,解决方案是通过在插件配置中添加以下行来排除清单签名文件:

<configuration>
    <filters>
        <filter>
            <artifact>*:*</artifact>
            <excludes>
                <exclude>META-INF/*.SF</exclude>
                <exclude>META-INF/*.DSA</exclude>
                <exclude>META-INF/*.RSA</exclude>
            </excludes>
        </filter>
    </filters>
    <!-- Additional configuration. -->
</configuration>

【讨论】:

  • 我在我的 uber-jar 中使用了这种方法,效果很好。 maven.apache.org/plugins/maven-shade-plugin/examples/… 有一个完整的 POM 示例,显示了此方法过滤包含的文件。
  • 我很想开始一个全新的线程 - 但由于这是 Google 搜索结果中的第一名 - 似乎很容易将其保留在这里。此处列出的行位于我正在使用的 POM 文件中 - 运行应用程序时仍然出现安全错误。正如预期的那样,它构建得很好 - 当然在不做 Uber jar 时运行得很好。虽然这当然是一种选择 - 将它们分开 - 如果你想要一个 Uber Jar,它并不能解决问题。
  • 这对我有用,但是...为什么我们必须忽略签名文件?我确定签名清单的存在是有原因的......
  • 上述操作后请务必执行“mvn clean”!
  • @JerylCook 签名文件在那里表明这个jar的内容有这些文件。当你制作一个 uber jar 时,你会在 jar 中添加更多文件,因此签名不正确。如果你真的想要,你可以重新签署新的罐子,但当然是你的签名,而不是旧的。或者,您不能分发 uber jar,而是将签名的 jar 作为单独的文件包含在内,但这首先违背了 uber jar 的目的。
【解决方案2】:

对于那些使用 gradle 并尝试创建和使用 fat jar 的人,以下语法可能会有所帮助。

jar {
    doFirst {
        from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } } 
    }
    exclude 'META-INF/*.RSA', 'META-INF/*.SF','META-INF/*.DSA' 
}

【讨论】:

  • 这基本上排除了 META-INF 目录中所有扩展名为 .RSA、.SF 或 .DSA 的文件。
  • 对 jar 文件进行签名会将这些文件添加到 META-INF 下,但是当它们被包含时,签名不再与 jar 内容一致。因此删除它们可以避免签名不匹配。
  • 有一个类似的问题严格关于在 gradle 中使用 fat jar - stackoverflow.com/questions/4871656/…
  • 这对我不起作用。我不得不将exclude 放到我的fatJar 任务中,该任务有configurations.compile.collect 命令。见stackoverflow.com/a/31426413/103412
  • 这也解决了错误Error: Could not find or load main class App Caused by: java.lang.ClassNotFoundException: App
【解决方案3】:

请使用以下命令

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

【讨论】:

  • 谢谢,我在使用 intellij 14 时遇到了这个问题,您的解决方案对我有用!
  • 谢谢,在 Windows 中为我工作。刚刚用 7zip 打开 jar,删除了 .SF 文件。我没有要删除的 .RSA 文件
  • 哇,我能说这个解决方案太棒了(而且我在此过程中学到了一些非常强大的东西!)这需要更多的支持。
  • 我同意@Dylan_Larkin 的评论,这就是为我解决的问题。
  • 应该是 zip -d yourjar.jar 'META-INF/*.SF' 'META-INF/*.RSA' 'META-INF/*DSA'
【解决方案4】:

您的某些依赖项可能是已签名的 jarfile。当您将它们全部组合成一个大 jarfile 时,相应的签名文件仍然存在,并且不再与“大组合”jarfile 匹配,因此运行时停止认为 jar 文件已被篡改(它......必须如此说话)。

假设您使用的是 ant,您可以通过从 jarfile 依赖项中删除签名文件来解决问题。不幸的是,it's not possible to do this in one step in ant

但是,我可以通过使用以下两个步骤来使用 Ant,而无需专门命名每个 jarfile 依赖项:

<target name="jar" depends="compile" description="Create one big jarfile.">
    <jar jarfile="${output.dir}/deps.jar">
        <zipgroupfileset dir="jars">
            <include name="**/*.jar" />
        </zipgroupfileset>
    </jar>
    <sleep seconds="1" />
    <jar jarfile="${output.dir}/myjar.jar" basedir="${classes.dir}">
        <zipfileset src="${output.dir}/deps.jar" excludes="META-INF/*.SF" />
        <manifest>
            <attribute name="Main-Class" value="com.mycompany.MyMain" />
        </manifest>
    </jar>
</target>

睡眠元素应该阻止errors about files with modification dates in the future

我在链接线程中发现的其他变体对我不起作用。

【讨论】:

  • 可以一步完成,使用不同的方式来指定你的 jars:
【解决方案5】:

这里列出的解决方案可能会提供一个指针。

Invalid signature file digest for Manifest main attributes

底线:

最好将官方 jar 保留为 是,只需将其作为依赖项添加到您的清单文件中 应用程序 jar 文件。

【讨论】:

  • 如何在清单文件中反映这一点?我以前从未编辑过。我用的是Xcode,一般的约定是把外部jar库放到myproject/lib目录下进行包含,我就是这么做的。
  • @user123003 .. 与 Intelli-J 一样
  • 不幸的是,我们中的一些人使用“maven shade plugin”之类的东西,所以在这些情况下包含原始 jar 的逐字副本并不容易......
  • this 网站上回答的无耻插件:stackoverflow.com/a/30922181/448779
  • maven-assembly-plugin 怎么样?在我的情况下它解决了这个问题
【解决方案6】:

我在使用 IntelliJ IDEA 14.01 时遇到了这个问题。

我能够通过以下方式修复它:

File->Project Structure->Add New (Artifacts)->jar->From Modules With Dependencies on the Create Jar From Module 窗口:

选择你的主要课程

来自库的 JAR 文件 选择复制到输出目录并通过清单链接

【讨论】:

  • 是否可以将依赖的jar放到目标jar中?
【解决方案7】:

安全性已经是一个棘手的话题,但我很失望地看到最流行的解决方案是删除安全签名。 JCE requires these signatures。 Maven shade 会爆炸 BouncyCastle jar 文件,该文件将签名放入 META-INF,但 BouncyCastle 签名对于新的 uber-jar 无效(仅适用于 BC jar),这就是导致 Invalid signature 错误的原因在这个线程中

是的,按照@ruhsuzbaykus 的建议排除或删除签名确实会使原始错误消失,但它也可能导致新的、神秘的错误:

java.security.NoSuchAlgorithmException: PBEWithSHA256And256BitAES-CBC-BC SecretKeyFactory not available

通过明确指定在哪里可以找到这样的算法:

SecretKeyFactory.getInstance("PBEWithSHA256And256BitAES-CBC-BC","BC");

我得到了一个不同的错误:

java.security.NoSuchProviderException: JCE cannot authenticate the provider BC

JCE 无法验证提供者,因为我们删除了加密签名 by following the suggestion elsewhere in this same thread

我找到的解决方案是 executable packer 插件,它使用 jar-in-jar 方法在单个可执行 jar 中保留 BouncyCastle 签名

更新

另一种方法(正确的方法?)是使用Maven Jar signer。这使您可以继续使用 Maven 阴影而不会出现安全错误。但是,您必须拥有代码签名证书(Oracle 建议搜索“Java 代码签名证书”)。 POM 配置如下所示:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-shade-plugin</artifactId>
    <version>3.1.0</version>
    <executions>
        <execution>
            <phase>package</phase>
            <goals>
                <goal>shade</goal>
            </goals>
            <configuration>
                <filters>
                    <filter>
                        <artifact>org.bouncycastle:*</artifact>
                        <excludes>
                            <exclude>META-INF/*.SF</exclude>
                            <exclude>META-INF/*.DSA</exclude>
                            <exclude>META-INF/*.RSA</exclude>
                        </excludes>
                    </filter>
                </filters>
                <transformers>
                    <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                        <mainClass>your.class.here</mainClass>
                    </transformer>
                </transformers>
                <shadedArtifactAttached>true</shadedArtifactAttached>
            </configuration>
        </execution>
    </executions>
</plugin>
<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-jarsigner-plugin</artifactId>
    <version>1.4</version>
    <executions>
        <execution>
            <id>sign</id>
            <goals>
                <goal>sign</goal>
            </goals>
        </execution>
        <execution>
            <id>verify</id>
            <goals>
                <goal>verify</goal>
            </goals>
        </execution>
    </executions>
    <configuration>
        <keystore>/path/to/myKeystore</keystore>
        <alias>myfirstkey</alias>
        <storepass>111111</storepass>
        <keypass>111111</keypass>
    </configuration>
</plugin>

不,没有办法让 JCE 识别自签名证书,因此如果您需要保留 BouncyCastle 证书,则必须使用 jar-in-jar 插件或获取 JCE 证书。

【讨论】:

  • 这绝对是正确的方法,即使它是工作密集型的。感谢您详细指出使用已批准答案的注意事项。您知道 JCE 证书是否必须由 Sun 签名吗?或者可以
  • 有第三方可以颁发代码签名证书。搜索“Java 代码签名证书”以查看选项。
  • 您,先生,成就了我的一天!
  • 为我提供帮助。这个库中有一些我不使用的文件,所以除了它们可以帮助我处理 fat-jar 文件
【解决方案8】:

我遇到了同样的问题,在某处参考后,它的工作方式如下更改:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-shade-plugin</artifactId>
    <version>3.2.1</version>
    <configuration>
        <createDependencyReducedPom>false</createDependencyReducedPom>
    </configuration>
    <executions>
        <execution>
            <phase>package</phase>
            <goals>
                <goal>shade</goal>
            </goals>
            <configuration>
                <filters>
                    <filter>
                        <artifact>*:*</artifact>
                        <excludes>
                            <exclude>META-INF/*.SF</exclude>
                            <exclude>META-INF/*.DSA</exclude>
                            <exclude>META-INF/*.RSA</exclude>
                        </excludes>
                    </filter>
                </filters>
            </configuration>
        </execution>
    </executions>
</plugin>

【讨论】:

  • 这很快解决了我的问题!为了完整起见,这应该放在maven-shade-plugin 标记中。
  • @Kuzeko 用您的建议更新了 anwser。谢谢
  • 感谢解决了我部署 java serverless 的问题
【解决方案9】:

假设您使用 ant 构建 jar 文件,您可以指示 ant 忽略 META-INF 目录。这是我的 ant 目标的简化版本:

<jar destfile="app.jar" basedir="${classes.dir}">
    <zipfileset excludes="META-INF/**/*" src="${lib.dir}/bcprov-jdk16-145.jar"></zipfileset>
    <manifest>
        <attribute name="Main-Class" value="app.Main"/>
    </manifest>
</jar>

【讨论】:

  • 我应该在哪里添加这些行?
【解决方案10】:

我最近开始在我的项目中使用 IntelliJ。但是,我的一些同事仍然在相同的项目中使用 Eclipse。今天,在执行我的 IntelliJ 创建的 jar 文件后,我遇到了同样的错误。虽然这里的所有解决方案都在谈论几乎相同的事情,但它们都不是很容易为我工作(可能是因为我不使用 ANT,maven build 给了我其他错误,这些错误将我引向http://cwiki.apache.org/confluence/display/MAVEN/MojoExecutionException,我也不能自己弄清楚签名的罐子是什么!)

终于this帮了我

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

猜猜我的 jar 文件中删除了什么?!

deleting: META-INF/ECLIPSE_.SF 
deleting: META-INF/ECLIPSE_.RSA

似乎该问题与某些与 eclipse 相关的文件有关。

【讨论】:

    【解决方案11】:

    我在创建胖 Jar 时在 gradle 中遇到了同样的问题,使用排除行更新 build.gradle 文件更正了该问题。

    jar {
        from {
            configurations.compile.collect {
                it.isDirectory() ? it : zipTree(it)
            }
        }
        exclude 'META-INF/*.RSA', 'META-INF/*.SF','META-INF/*.DSA'
        manifest {
            attributes 'Main-Class': 'com.test.Main'
        }
    }
    

    【讨论】:

    • 我调试了好几天,这解决了我的胖罐问题。
    • 我调试的方式是把fat jar放到jmeter lib目录下。如果您在 lib/ext 中有问题的 jar,则此问题不会很明显,而是会出现类似 stackoverflow.com/questions/37624187/… 中的错误
    • exclude 'META-INF/*.RSA', 'META-INF/*.SF','META-INF/*.DSA' 这是缺失的,一些依赖的 jar 导致了问题
    【解决方案12】:

    如果您使用的是 gradle,这里有一个完整的 farJar 任务:

    version = '1.0'
    //create a single Jar with all dependencies
    task fatJar(type: Jar) {
        manifest {
            attributes 'Implementation-Title': 'Gradle Jar File Example',  
                'Implementation-Version': version,
                'Main-Class': 'com.example.main'
        }
        baseName = project.name + '-all'
        from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } }
        exclude 'META-INF/*.RSA', 'META-INF/*.SF','META-INF/*.DSA' 
        with jar
    }
    

    【讨论】:

      【解决方案13】:

      将新 jar 中的 META-INF 文件夹与旧 jar 进行比较(在添加新库之前)。可能会有新文件。如果是,您可以删除它们。它应该有帮助。 问候, 999麦尔

      【讨论】:

        【解决方案14】:

        一种策略包括使用 ANT 来简化从每个 Jar 文件中删除签名的过程。它将执行以下步骤:

        1. 将 MANIFEST.MF 复制到临时文件中
        2. 从临时文件中删除 NameSHA 条目
        3. 使用临时清单创建临时 Jar 文件
        4. 删除临时清单
        5. 用临时 Jar 文件交换原始 Jar 文件

        这里有一个ANT macrodef 在做这项工作:

        <macrodef name="unsignjar" description="To unsign a specific Jar file">
            <attribute name="jarfile" 
                description="The jar file to unsign" />
            <sequential>
        <!-- Copying to the temporary manifest file -->
                <copy toFile="@{jarFile}_MANIFEST.tmp">
                    <resources>
                        <zipentry zipfile="@{jarFile}" name="META-INF/MANIFEST.MF"/>
                    </resources>
                </copy>
        <!-- Removing the Name and SHA entries from the temporary file -->
                <replaceregexp file="@{jarFile}_MANIFEST.tmp" match="\nName:(.+?)\nSH" replace="SH" flags="gis" byline="false"/>
                <replaceregexp file="@{jarFile}_MANIFEST.tmp" match="SHA(.*)" replace="" flags="gis" byline="false"/>
        <!-- Creating a temporary Jar file with the temporary manifest -->
                <jar jarfile="@{jarFile}.tmp"
                    manifest="@{jarFile}_MANIFEST.tmp">
                    <zipfileset src="@{jarFile}">
                        <include name="**"/>
                        <exclude name="META-INF/*.SF"/>
                        <exclude name="META-INF/*.DSA"/>
                        <exclude name="META-INF/*.RSA"/>
                    </zipfileset>
                </jar>
        <!-- Removing the temporary manifest -->
                <delete file="@{jarFile}_MANIFEST.tmp" />
        <!-- Swapping the original Jar file with the temporary one -->
                <move file="@{jarFile}.tmp"
                      tofile="@{jarFile}"
                      overwrite="true" />
        </sequential>
        

        `

        然后可以在 ANT 任务中以这种方式调用定义:

        <target name="unsignJar">
            <unsignjar jarFile="org.test.myjartounsign.jar" />
        </target>
        

        【讨论】:

          【解决方案15】:

          错误:发生 JNI 错误,请检查您的安装并重试 线程“main”中的异常 java.lang.SecurityException:Manifest 主要属性的签名文件摘要无效 在 sun.security.util.SignatureFileVerifier.processImpl(SignatureFileVerifier.java:314) 在 sun.security.util.SignatureFileVerifier.process(SignatureFileVerifier.java:268) 在 java.util.jar.JarVerifier.processEntry(JarVerifier.java:316) 在 java.util.jar.JarVerifier.update(JarVerifier.java:228) 在 java.util.jar.JarFile.initializeVerifier(JarFile.java:383) 在 java.util.jar.JarFile.getInputStream(JarFile.java:450) 在 sun.misc.URLClassPath$JarLoader$2.getInputStream(URLClassPath.java:977) 在 sun.misc.Resource.cachedInputStream(Resource.java:77) 在 sun.misc.Resource.getByteBuffer(Resource.java:160) 在 java.net.URLClassLoader.defineClass(URLClassLoader.java:454) 在 java.net.URLClassLoader.access$100(URLClassLoader.java:73) 在 java.net.URLClassLoader$1.run(URLClassLoader.java:368) 在 java.net.URLClassLoader$1.run(URLClassLoader.java:362) 在 java.security.AccessController.doPrivileged(本机方法) 在 java.net.URLClassLoader.findClass(URLClassLoader.java:361) 在 java.lang.ClassLoader.loadClass(ClassLoader.java:424) 在 sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331) 在 java.lang.ClassLoader.loadClass(ClassLoader.java:357) 在 sun.launcher.LauncherHelper.checkAndLoadMain(LauncherHelper.java:495)

          对我有什么帮助(IntelliJ IDEA 2016.3): 文件 -> 项目结构 -> 工件 -> 添加 JAR -> 选择主类 -> 选择“复制到输出目录并通过清单链接” -> 确定 -> 应用 -> 构建 -> 构建工件... -> 构建

          【讨论】:

            【解决方案16】:

            有可能两个不同的签名者搞乱了 java 的思维。

            尝试从 jar 中删除 META-INF 文件夹,添加清单并再次签署 JAR,它帮助了我:http://jehy.ru/articles/2013/12/13/invalid-signature-file-digest-for-manifest-main-attributes/

            【讨论】:

            • +1 链接。从我正在使用的 jar 中删除 META-INF*.RSA 和 META-INF*.SF 为我解决了这些问题。 YMMV
            【解决方案17】:

            如果您正在寻找无需解压或篡改原始库但具有特殊 JAR 类加载器的 Fat JAR 解决方案,请查看my project here

            免责声明:我没有编写代码,只是将其打包并发布在 Maven Central 上,并在我的自述文件中描述如何使用它。

            我个人使用它来创建包含 BouncyCastle 依赖项的可运行 uber JAR。也许它对你也有用。

            【讨论】:

              【解决方案18】:

              对于那些对已接受的解决方案有疑问的人,还有另一种方法可以使用 DontIncludeResourceTransformer 从阴影 jar 中排除资源:

              https://maven.apache.org/plugins/maven-shade-plugin/examples/resource-transformers.html#DontIncludeResourceTransformer

                        <transformers>
                          <transformer implementation="org.apache.maven.plugins.shade.resource.DontIncludeResourceTransformer">
                              <resource>BC1024KE.DSA</resource>
                          </transformer>
                        </transformers>
              

              从 Shade 3.0 开始,此转换器接受资源列表。在此之前,您只需要使用多个转换器,每个转换器具有一个资源。

              【讨论】:

                【解决方案19】:

                当我在 Intellij 说“找到非托管 pom 文件”时单击底部的“添加为 Maven 项目”时,Intellij 发生了这种情况。同时out文件夹已经生成。所以它没有得到最近的变化。

                删除文件夹并运行程序为我解决了这个问题。然后重新创建了 out 文件夹。

                也见小狐狸的回答。我收到的错误与他的非常相似。

                【讨论】:

                  【解决方案20】:

                  你可以使用Shadow来生成jar。

                  Shadow 是一个 Gradle 插件,用于将项目的依赖类和资源组合到单个输出 Jar 中。组合的 Jar 通常称为 fat-jar 或 uber-jar。

                  1. 修改build.gradle

                    plugins {
                        ...
                        // ① Add the shadow plugin
                        id "com.github.johnrengelman.shadow" version "5.2.0"
                    }
                    
                    ...
                    // ② Config the shadow jar, its name is baseName-1.0-classifier.jar
                    shadowJar {
                        archiveBaseName.set('baseName')
                        archiveClassifier.set('classifier')
                        archiveVersion.set('1.0')
                        manifest {
                            attributes 'Main-Class': 'Main'
                        }
                    }
                    
                    // ③ Disable the default jar task
                    jar.enabled = false
                    // ④ Execute the shadowJar task when compiling
                    build.dependsOn(shadowJar)
                    
                  2. 执行命令gradle build,会生成jar文件:

                    • /build/libs/baseName-1.0-classifier.jar

                  【讨论】:

                    【解决方案21】:

                    我遇到了类似的问题。原因是我使用的 JDK 与我的 Windows 框中的默认 JRE 不同。

                    使用正确的 java.exe 解决了我的问题。

                    【讨论】:

                      【解决方案22】:

                      如果您在尝试为 Xamarin.Android 绑定项目绑定 JAR 文件时遇到此问题:

                      JARTOXML:警告 J2XA006:在反映 com.your.class 时引发了缺少类错误:Manifest 主要属性的签名文件摘要无效

                      只需使用 Winzip 打开 JAR 文件并删除 meta-inf 目录。重建 - 工作完成

                      【讨论】:

                      • 这是一种可怕的技术。绝对可怕。在本地进行更正,不要对传入的 jar 进行更改
                      猜你喜欢
                      • 2011-11-14
                      • 1970-01-01
                      • 2016-04-23
                      • 2021-09-28
                      • 1970-01-01
                      • 2012-07-28
                      • 2014-10-22
                      • 2019-04-13
                      相关资源
                      最近更新 更多