You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Java Web应用SSL与数字签名配置求助:含dummy证书生成及HTTPS设置

嗨,我来一步步帮你理清这些知识点——毕竟从HTTP认证转到SSL和数字签名确实有个门槛,我当初刚接触的时候也踩过不少坑😉

一、先搞懂核心概念

先区分下两个容易混淆的点,避免搞混:

  • SSL/HTTPS:属于传输层的加密协议,解决的是数据在网络传输过程中被窃听、篡改的问题,同时能验证服务器身份(也可扩展验证客户端)。
  • 数字签名:是应用层的安全手段,用来验证数据的完整性(没被篡改)和身份真实性(确实是目标主体发出的),和SSL是互补关系,而非替代。
二、创建Dummy(测试用)SSL证书

Java自带的keytool工具就能搞定,不用额外装软件,步骤如下:

  1. 生成自签名密钥库(包含私钥和证书)
    打开终端/命令行,执行以下命令:

    keytool -genkeypair -alias my-dummy-cert -keyalg RSA -keysize 2048 -storetype PKCS12 -keystore dummy-keystore.p12 -validity 365
    

    关键参数解释:

    • -alias:证书的别名,用来区分密钥库里的不同证书
    • -keyalg RSA:采用RSA加密算法,安全性足够满足测试需求
    • -storetype PKCS12:当前推荐的密钥库格式,跨平台兼容性比老的JKS更好
    • -validity 365:证书有效期365天,测试用完全足够
      执行后会让你输入密钥库密码、姓名、组织等信息,随便填写即可,测试场景不用较真。
  2. (可选)导出证书给客户端信任
    如果要让浏览器等客户端信任这个测试证书,避免弹出“不安全”警告,可以导出证书文件:

    keytool -exportcert -alias my-dummy-cert -keystore dummy-keystore.p12 -file dummy-cert.crt -storetype PKCS12
    

    把生成的.crt文件导入到浏览器的信任列表即可。

三、Java Web应用配置HTTPS

分两种常见场景给你说明:

1. 传统Servlet应用(部署在Tomcat)

找到Tomcat的conf/server.xml文件,添加HTTPS的Connector配置:

<Connector port="8443" protocol="org.apache.coyote.http11.Http11NioProtocol"
           maxThreads="150" SSLEnabled="true">
    <SSLHostConfig>
        <Certificate certificateKeystoreFile="conf/dummy-keystore.p12"
                     type="RSA"
                     certificateKeystorePassword="你刚才设置的密钥库密码"
                     certificateKeystoreType="PKCS12"/>
    </SSLHostConfig>
</Connector>

把生成的dummy-keystore.p12放到Tomcat的conf目录下,重启Tomcat后,就可以通过https://localhost:8443/你的应用路径访问了。

2. Spring Boot应用

直接在application.properties(或application.yml)里配置即可:

# 启用HTTPS端口
server.port=8443
# 指定密钥库路径(放在resources目录下用classpath:前缀)
server.ssl.key-store=classpath:dummy-keystore.p12
# 密钥库密码
server.ssl.key-store-password=你的密码
# 密钥库类型
server.ssl.key-store-type=PKCS12
# 证书别名
server.ssl.key-alias=my-dummy-cert

启动Spring Boot后,直接访问https://localhost:8443即可。如果需要同时支持HTTP和HTTPS,可以额外配置HTTP端口,再通过配置类把HTTP请求重定向到HTTPS。

四、数字签名在Java Web中的应用

数字签名的核心逻辑是私钥签名,公钥验证——私钥由签名方妥善保管,公钥对外公开。下面给你一个Web场景下的实用示例:

1. 生成密钥对(可提前生成或应用启动时生成)

import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;

public class KeyPairUtil {
    public static KeyPair generateRSAKeyPair() throws NoSuchAlgorithmException {
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
        keyPairGenerator.initialize(2048); // 2048位密钥安全性足够
        return keyPairGenerator.generateKeyPair();
    }
}

2. 签名与验证工具类

import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.nio.charset.StandardCharsets;

public class SignatureUtil {
    // 用私钥签名数据
    public static byte[] signData(String data, PrivateKey privateKey) throws Exception {
        Signature signature = Signature.getInstance("SHA256withRSA"); // SHA256哈希+RSA签名组合
        signature.initSign(privateKey);
        signature.update(data.getBytes(StandardCharsets.UTF_8));
        return signature.sign();
    }

    // 用公钥验证签名
    public static boolean verifySignature(String data, byte[] signedData, PublicKey publicKey) throws Exception {
        Signature signature = Signature.getInstance("SHA256withRSA");
        signature.initVerify(publicKey);
        signature.update(data.getBytes(StandardCharsets.UTF_8));
        return signature.verify(signedData);
    }
}

3. Spring MVC接口示例

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.security.KeyPair;
import java.util.Base64;

@RestController
public class SignatureController {
    // 提前生成密钥对(生产环境建议存在配置中心或密钥管理系统)
    private static final KeyPair keyPair;

    static {
        try {
            keyPair = KeyPairUtil.generateRSAKeyPair();
        } catch (Exception e) {
            throw new RuntimeException("生成密钥对失败", e);
        }
    }

    @GetMapping("/api/sensitive-data")
    public SensitiveDataResponse getSensitiveData() throws Exception {
        String data = "这是敏感数据,不能被篡改";
        // 对数据签名
        byte[] signedData = SignatureUtil.signData(data, keyPair.getPrivate());
        // 返回数据和Base64编码后的签名(方便网络传输)
        return new SensitiveDataResponse(data, Base64.getEncoder().encodeToString(signedData));
    }

    // 对外提供公钥,供客户端验证签名
    @GetMapping("/api/public-key")
    public String getPublicKey() {
        return Base64.getEncoder().encodeToString(keyPair.getPublic().getEncoded());
    }
}

// 响应实体类
class SensitiveDataResponse {
    private String data;
    private String signature;

    // 构造方法、getter/setter省略
}

客户端拿到数据和签名后,调用/api/public-key获取公钥,就可以验证数据是否来自服务端、是否被篡改了。

五、重点注意事项
  • Dummy证书仅用于测试:生产环境必须使用权威CA(比如Let's Encrypt、Symantec等)颁发的证书,否则浏览器会提示不安全,用户不敢访问。
  • SSL与数字签名互补:SSL解决传输安全,数字签名解决数据本身的真实性和完整性——即使走HTTPS传输,也可以用数字签名确保数据在服务端生成后没被篡改。
  • 密钥需妥善保管:私钥绝对不能泄露,公钥可放心对外公开;生产环境建议用专门的密钥管理系统(KMS)存储私钥,不要硬编码在代码里。

内容的提问来源于stack exchange,提问作者Pravat

火山引擎 最新活动