尝试运行.jar时出现“无效签名文件”


450

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

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

我在Google上搜索了一个多小时,一直在寻找解释,却发现价值不大。如果有人以前曾见过此错误并可以提供帮助,我将有义务。


1
您是否要签名自己的罐子?如果是这样,您打算如何签名?
Cogsy

不,至少我不认为我是。Xcode可能试图自行对其进行签名,但是似乎没有任何设置可以关闭它。

不要忘记检查包含已实现接口的jar是否也已签名!
gaurav

Answers:


47

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

清单主要属性的签名文件摘要无效

底线:

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


3
我将如何在清单文件中反映出来?我以前从未编辑过。我正在使用Xcode,通用约定是将外部jar库放在myproject / lib目录中以进行包含,这就是我正在做的事情。

@ user123003 ..就像Intelli-J一样
MikeM 2014年

13
不幸的是,我们中的一些人使用诸如“ maven shade plugin”之类的东西,因此在这些情况下包括原始jar的逐字记录并不是那么容易...
rogerdpack 2015年

无耻的插头在这个网站上回答:stackoverflow.com/a/30922181/448779
foo

那Maven-assembly-plugin呢?它解决了我的问题
jhenya-d

1082

对于那些谁得到了试图创建一个当这个错误尤伯杯罐子maven-shade-plugin,解决的办法是通过添加以下行插件配置排除清单签名文件:

<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>

9
我将这种方法用于uber-jar,效果很好。在maven.apache.org/plugins/maven-shade-plugin/examples/…上有一个完整的POM示例,其中显示了此方法可过滤包含的文件。
M. Dudley

4
我很想开始一个全新的话题-但由于这是Google搜索结果中的第一名-因此似乎很容易将其保留在这里。此处列出的行在我正在使用的POM文件中-运行应用程序时仍然出现安全错误。正如预期的那样,它构建良好-并且在不使用Uber jar时当然可以运行良好。而且,尽管这当然是一个选择-将它们分开放置-如果您想要一个Uber Jar并不能解决问题。
加文·鲍马尼斯

7
这对我有用,但是...为什么我们必须忽略签名文件?我敢肯定的签名明显是有原因的....
病毒Jery​​l库克

4
完成上述操作后,请确保执行“ MVN清洁”!
codeinjuice

4
@JerylCook签名文件用于指示此jar的内容包含这些文件。制作uber jar时,要向jar添加更多文件,因此签名不正确。如果您确实需要,可以重新签名新的jar,但是当然可以使用您的签名,而不是旧的签名。或者,您不能分发uber jar,而只能将签名的jar作为单独的文件包含在内,但这首先违背了uber jar的目的。
LadyCailin

139

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

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

1
这只是基本上排除了META-INF目录中所有扩展名为.RSA,.SF或.DSA的文件。
Keith P

9
对jar文件进行签名会在META-INF下添加这些文件,但是当包含它们时,签名将不再与jar内容一致。因此删除它们可以避免签名不匹配。
Peter N. Steinmetz

1
有严格的关于使用gradle这个罐子脂肪类似的问题- stackoverflow.com/questions/4871656/...
托马斯Sętkowski

3
这对我不起作用。我不得不把exclude我的fatJar任务,其中有这样的configurations.compile.collect命令。请参阅stackoverflow.com/a/31426413/103412
Torsten,

1
这也解决了错误Error: Could not find or load main class App Caused by: java.lang.ClassNotFoundException: App
vonox7

56

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

您可以通过从jarfile依赖项中消除签名文件来解决问题。不幸的是,在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>

应该使用sleep元素来防止将来具有修改日期的文件出错

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


可以通过一种不同的方式一步一步指定您的jar:<jar destfile =“ build / myjar.jar”> <restrict> <not> <name name =“ META-INF / *。SF” /> </ not> <archives> <zips> <fileset dir =“ jarfolder” includes =“ * / .jar” /> </ zips> </ archives> </ restrict> </ jar>
DieterDP

56

请使用以下命令

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

4
谢谢,我在intellij 14中遇到了这个问题,您的解决方案对我有效!
Mohamad Kouhi Moghadam

5
谢谢您在Windows中为我工作。刚刚用7zip打开了jar,删除了.SF文件。我没有任何要删除的.RSA文件
candino

3
哇,我能说这个解决方案很棒吗(我在此过程中学到了非常强大的知识!)这需要更多的支持。
Dylan_Larkin

我同意@Dylan_Larkin的评论,这就是为我解决的问题。
Felipe Valdes

26

使用IntelliJ IDEA 14.01时出现此问题。

我可以通过以下方式修复它:

File-> Project Structure-> Add new(Artifacts)-> jar-> From Modules并具有从模块窗口中创建Jar的相关性:

选择你的主班

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


2
是否可以将依赖的jar放入目标jar?
coder.chenzhi17年

您的解决方案效果很好!非常感谢!
hzitoun

19

安全性已经是一个艰巨的话题,但是令我失望的是,最受欢迎的解决方案是删除安全性签名。JCE需要这些签名。Maven阴影会爆炸BouncyCastle jar文件,该文件会将签名放入META-INF中,但是BouncyCastle签名对于新的uber-jar无效(仅对于BC jar),这就是导致此线程中的Invalid签名错误的原因

是的,按照@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无法对提供者进行身份验证,因为我们已经 按照同一线程中其他地方的建议删除了加密签名

我找到的解决方案是可执行打包程序插件,该插件使用jar-in-jar方法将BouncyCastle签名保留在单个可执行jar中。

更新

另一种方法(正确的方法?)是使用Maven Jar签名器。这使您可以继续使用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签名吗?或者可以
WiteCastle

1
有第三方可以颁发代码签名证书。搜索“ Java代码签名证书”以查看选项。
MattW

您,先生,我过得愉快!
socona

对我有帮助。该库中有一些我不使用的文件,因此除了它们可以帮助我处理胖子文件外
Saidolim

14

在引用某处后,我遇到了同样的问题,它的工作方式如下所示:

<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>

1
这很快解决了我的问题!为了完整起见,这应该放在maven-shade-plugin标记中。
库泽科

1
@Kuzeko用您的建议更新了anwser。谢谢
m.nguyencntt '19

8

假设您使用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>

我应该在哪里添加这些行?
Addi.Star

4

我最近开始在项目中使用IntelliJ。但是,我的一些同事仍然在同一项目上使用Eclipse。今天,执行我的IntelliJ创建的jar文件后,我遇到了同样的错误。尽管这里的所有解决方案都在谈论几乎同一件事,但它们都不适合我(可能是因为我不使用ANT,Maven构建给我带来了其他错误,这些错误将我http://cwiki.apache.org/ confluence / display / MAVEN / MojoExecutionException,而且我自己也不清楚已签名的罐子是什么!)

最后,对我有帮助

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

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

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

似乎该问题与某些与日食有关的文件有关。


4

gradle创建胖Jar时,我遇到了相同的问题,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'
    }
}

1
我调试了几天,这解决了我的胖子问题。
sysuser

我调试的方法是将胖子jar放在jmeter lib目录中。如果您在lib / ext目录有问题的罐子,这个问题不会很明显,而你会得到像在一个错误stackoverflow.com/questions/37624187/...
SYSUSER

1
排除“ META-INF / *。RSA”,“ META-INF / *。SF”,“ META-INF / *。DSA”这是丢失的,某些依赖的jar引起了问题
Nirbhay Mishra

3

如果您使用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
}

2

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


2

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

  1. 将MANIFEST.MF复制到一个临时文件中
  2. 从临时文件中删除名称SHA条目
  3. 使用临时清单创建临时Jar文件
  4. 删除临时清单
  5. 将原始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>

2

错误:发生了JNI错误,请检查安装情况,然后重试。线程“主”中的异常java.lang.SecurityException:sun.security.util.SignatureFileVerifier.processImpl(SignatureFileVerifier.java:中清单主要属性的无效签名文件摘要: 314)在java.util.jar.JarVerifier.processEntry(JarVerifier.java:316)在sun.security.util.SignatureFileVerifier.process(SignatureFileVerifier.java:268)在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)at java.net.URLClassLoader.defineClass(URLClassLoader.java:454)at java.net.URLClassLoader.access $ 100(URLClassLoader.java:73)at java.net.URLClassLoader $ 1.run(URLClassLoader.java:368)at java.net.URLClassLoader.findClass(URLClassLoader.java:361)上的java.net.URLClassLoader.findClass(URLClassLoader.java:361)上的java.net.URLClassLoader $ 1.run(URLClassLoader.java:362) (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)在java.net.URLClassLoader处运行(URLClassLoader.java:368)$1。在java.net.URLClassLoader.findClass(URLClassLoader.java:361处的java.security.AccessController.doPrivileged(本机方法)处运行(URLClassLoader.java:362) )的java.lang.ClassLoader.loadClass(ClassLoader.java:424)在sun.misc.Launcher $ AppClassLoader.loadClass(Launcher.java:331)在java.lang.ClassLoader.loadClass(ClassLoader.java:357)在.launcher.LauncherHelper.checkAndLoadMain(LauncherHelper.java:495)在java.net.URLClassLoader处运行(URLClassLoader.java:368)$1。在java.net.URLClassLoader.findClass(URLClassLoader.java:361处的java.security.AccessController.doPrivileged(本机方法)处运行(URLClassLoader.java:362) )的java.lang.ClassLoader.loadClass(ClassLoader.java:424)在sun.misc.Launcher $ AppClassLoader.loadClass(Launcher.java:331)在java.lang.ClassLoader.loadClass(ClassLoader.java:357)在.launcher.LauncherHelper.checkAndLoadMain(LauncherHelper.java:495)331),位于sun.launcher.LauncherHelper.checkAndLoadMain(LauncherHelper.java:495)的java.lang.ClassLoader.loadClass(ClassLoader.java:357)331),位于sun.launcher.LauncherHelper.checkAndLoadMain(LauncherHelper.java:495)的java.lang.ClassLoader.loadClass(ClassLoader.java:357)

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



1

如果您在寻找不解包或篡改原始库但使用特殊JAR类加载器的Fat JAR解决方案,请在此处查看我的项目

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

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


0

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

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开始,此转换器接受资源列表。在此之前,您只需要使用多个变压器,每个变压器只有一个资源。


0

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

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

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


-1

我有一个类似的问题。原因是我在Windows框中使用的JDK与默认JRE不同。

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


-2

如果在尝试为Xamarin.Android绑定项目绑定JAR文件时遇到这种情况,请执行以下操作:

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

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


1
这是一种可怕的技术。绝对可怕。本地进行更正不会更改传入的jar
sinisterrook
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.