Java代码签名案例

wen java案例 3

本文目录导读:

Java代码签名案例

  1. 准备工作
  2. Java代码签名示例
  3. 签名JAR文件
  4. 权限策略配置
  5. Maven项目示例
  6. 完整示例代码
  7. 验证签名信息
  8. 最佳实践建议

我来为您介绍一个Java代码签名(Code Signing)的完整案例,涵盖从生成证书到签名打包的全过程。

准备工作

1 使用keytool生成自签名证书

# 生成密钥库和自签名证书
keytool -genkey -alias mykey -keyalg RSA -keysize 2048 -keystore mykeystore.jks -validity 365
# 参数说明:
# -alias: 密钥别名
# -keyalg: 加密算法
# -keysize: 密钥长度
# -keystore: 密钥库文件名
# -validity: 有效期(天)

2 查看生成的证书

# 查看密钥库内容
keytool -list -v -keystore mykeystore.jks
# 导出证书(可选)
keytool -export -alias mykey -keystore mykeystore.jks -file mycert.crt

Java代码签名示例

1 创建需要签名的Java程序

// MainApplication.java
import javax.swing.*;
import java.awt.*;
import java.security.AccessController;
import java.security.PrivilegedAction;
public class MainApplication extends JFrame {
    public MainApplication() {
        setTitle("代码签名示例");
        setSize(400, 300);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        JPanel panel = new JPanel();
        JButton btn = new JButton("执行特权操作");
        btn.addActionListener(e -> {
            // 需要特权的操作
            String result = AccessController.doPrivileged(
                (PrivilegedAction<String>) () -> {
                    // 这里执行需要特权的操作
                    return System.getProperty("user.name");
                }
            );
            JOptionPane.showMessageDialog(this, "当前用户: " + result);
        });
        panel.add(btn);
        add(panel);
    }
    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> {
            new MainApplication().setVisible(true);
        });
    }
}

2 编译Java程序

# 编译Java文件
javac MainApplication.java
# 打JAR包
jar cvf myapp.jar *.class

签名JAR文件

1 使用jarsigner签名

# 基本签名命令
jarsigner -keystore mykeystore.jks -storepass 密码 -keypass 密码 myapp.jar mykey
# 使用时间戳服务器(推荐)
jarsigner -keystore mykeystore.jks -tsa http://timestamp.digicert.com myapp.jar mykey
# 签名后验证
jarsigner -verify myapp.jar

2 完整的签名脚本

#!/bin/bash
# sign_jar.sh
KEYSTORE="mykeystore.jks"
STORE_PASS="your_keystore_password"
KEY_PASS="your_key_password"
ALIAS="mykey"
JAR_FILE="myapp.jar"
TSA_URL="http://timestamp.digicert.com"
echo "开始签名JAR文件..."
# 签名
jarsigner -keystore $KEYSTORE \
          -storepass $STORE_PASS \
          -keypass $KEY_PASS \
          -tsa $TSA_URL \
          $JAR_FILE $ALIAS
# 验证签名
echo "验证签名..."
jarsigner -verify -verbose -certs $JAR_FILE
if [ $? -eq 0 ]; then
    echo "签名成功且验证通过!"
else
    echo "签名验证失败!"
    exit 1
fi

权限策略配置

1 创建策略文件

// myapp.policy
grant codeBase "file:/path/to/myapp.jar" {
    permission java.util.PropertyPermission "user.name", "read";
    permission java.util.PropertyPermission "user.home", "read";
    permission java.io.FilePermission "/tmp/*", "read,write";
    permission java.net.SocketPermission "localhost:1024-", "connect";
};

2 使用策略文件运行

# 使用安全策略运行
java -Djava.security.policy=myapp.policy -jar myapp.jar
# 或使用安全管理器
java -Djava.security.manager -Djava.security.policy=myapp.policy -jar myapp.jar

Maven项目示例

1 pom.xml配置

<project>
    <build>
        <plugins>
            <!-- Maven JAR Plugin -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-jar-plugin</artifactId>
                <configuration>
                    <archive>
                        <manifest>
                            <mainClass>com.example.MainApplication</mainClass>
                        </manifest>
                    </archive>
                </configuration>
            </plugin>
            <!-- Maven Jarsigner Plugin -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-jarsigner-plugin</artifactId>
                <version>3.0.0</version>
                <executions>
                    <execution>
                        <id>sign</id>
                        <phase>package</phase>
                        <goals>
                            <goal>sign</goal>
                        </goals>
                        <configuration>
                            <keystore>${basedir}/mykeystore.jks</keystore>
                            <alias>mykey</alias>
                            <storepass>${keystore.password}</storepass>
                            <keypass>${key.password}</keypass>
                            <tsa>http://timestamp.digicert.com</tsa>
                        </configuration>
                    </execution>
                    <execution>
                        <id>verify</id>
                        <phase>verify</phase>
                        <goals>
                            <goal>verify</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>

完整示例代码

1 安全检查示例

// SecurityCheckExample.java
import java.security.*;
import javax.swing.*;
public class SecurityCheckExample {
    public static void main(String[] args) {
        // 检查是否有签名
        CodeSource cs = SecurityCheckExample.class.getProtectionDomain().getCodeSource();
        if (cs != null) {
            java.security.cert.Certificate[] certs = cs.getCertificates();
            if (certs != null) {
                System.out.println("代码已签名,证书数量: " + certs.length);
                for (java.security.cert.Certificate cert : certs) {
                    System.out.println("证书类型: " + cert.getType());
                }
            } else {
                System.out.println("警告: 代码未签名!");
                JOptionPane.showMessageDialog(null, 
                    "未签名的应用程序可能受限", 
                    "安全警告", 
                    JOptionPane.WARNING_MESSAGE);
            }
        }
    }
}

2 权限请求示例

// PermissionRequestExample.java
import java.security.*;
import javax.swing.*;
public class PermissionRequestExample {
    public static void requestFilePermission() {
        try {
            // 请求文件读取权限
            Permission perm = new java.io.FilePermission("/etc/passwd", "read");
            AccessController.checkPermission(perm);
            System.out.println("权限检查通过");
        } catch (AccessControlException e) {
            System.out.println("权限不足: " + e.getMessage());
            JOptionPane.showMessageDialog(null,
                "需要额外的权限来执行此操作",
                "权限请求",
                JOptionPane.INFORMATION_MESSAGE);
        }
    }
    public static void main(String[] args) {
        requestFilePermission();
    }
}

验证签名信息

1 程序化验证

// VerifySignature.java
import java.util.jar.*;
import java.security.cert.*;
import java.io.*;
public class VerifySignature {
    public static boolean verifyJarSignature(String jarPath) {
        try (JarFile jar = new JarFile(jarPath, true)) {
            Enumeration<JarEntry> entries = jar.entries();
            while (entries.hasMoreElements()) {
                JarEntry entry = entries.nextElement();
                // 跳过目录和签名相关文件
                if (entry.isDirectory() || 
                    entry.getName().startsWith("META-INF/")) {
                    continue;
                }
                // 验证条目签名
                Certificate[] certs = entry.getCertificates();
                if (certs == null) {
                    System.out.println("未签名条目: " + entry.getName());
                    return false;
                }
                // 验证证书链
                for (Certificate cert : certs) {
                    if (cert instanceof X509Certificate) {
                        X509Certificate x509Cert = (X509Certificate) cert;
                        try {
                            x509Cert.checkValidity();
                            System.out.println("证书有效: " + 
                                x509Cert.getSubjectDN());
                        } catch (CertificateExpiredException e) {
                            System.out.println("证书已过期: " + 
                                x509Cert.getSubjectDN());
                            return false;
                        }
                    }
                }
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
    public static void main(String[] args) {
        if (args.length > 0) {
            boolean isValid = verifyJarSignature(args[0]);
            System.out.println("签名验证结果: " + (isValid ? "通过" : "失败"));
        }
    }
}

最佳实践建议

  1. 使用时间戳:避免证书过期后签名失效
  2. 密码管理:不要在代码中硬编码密码,使用环境变量或配置文件
  3. 证书备份:妥善保管密钥库文件
  4. 定期更新:证书过期前更新签名
  5. 最小权限:只授予必要的最小权限

这个案例展示了Java代码签名从生成证书到签名验证的完整流程,实际生产环境中建议使用权威CA(如DigiCert、GlobalSign)颁发的代码签名证书。

抱歉,评论功能暂时关闭!