自签名SSL证书生成
步骤 1:生成服务器私钥
首先,生成服务器私钥文件:
bash
openssl genrsa -out server.key 2048
这会生成一个 2048 位的私钥文件 server.key
。
步骤 2:生成证书签名请求(CSR)
使用上一步生成的私钥创建一个 CSR 文件,用来告诉证书颁发者证书的信息(包括主机名)。
bash
openssl req -new -key server.key -out server.csr
执行该命令后,会提示输入一些信息,如:
- Country Name (2 letter code) : 国家代码,如
CN
(中国) - State or Province Name (full name): 省份
- Locality Name (eg, city): 城市
- Organization Name (eg, company): 公司或组织名称
- Organizational Unit Name (eg, section): 部门
- Common Name (e.g. server FQDN or YOUR name) : 这点非常重要,应该填写服务器的域名或主机名。例如,假如你连接的是
localhost
,请将这里填写为localhost
。
步骤 3:生成自签名证书
使用生成的 CSR 文件生成自签名的服务器证书:
bash
openssl x509 -req -in server.csr -signkey server.key -out server.crt -days 365
这会生成一个有效期为 365 天的自签名证书 server.crt
。
步骤 4:数据库配置 SSL------以Kingbase为例
在生成的证书和私钥后,更新你的 kingbase.confssl
文件的相关配置:
ini
ssl = on
ssl_cert_file = 'D:\\card\\server.crt'
ssl_key_file = 'D:\\card\\server.key'
ssl_ciphers = 'ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE'
ssl_prefer_server_ciphers = on
ssl_min_protocol_version = 'TLSv1.2'
ssl_max_protocol_version = ''
如果你是在 Windows 环境下,需要确保路径是使用 \\
作为路径分隔符。
更新你的sys_hba.conf:限制只能通过ssl连接
ini
hostssl all all 127.0.0.1/32 scram-sha-256
hostssl all all 0.0.0.0/0 scram-sha-256
hostssl all all ::1/128 scram-sha-256
hostssl all all ::0/0 scram-sha-256
hostssl replication all 127.0.0.1/32 scram-sha-256
hostssl replication all ::1/128 scram-sha-256
步骤 5:更新 Spring Boot 配置
更新 Spring Boot 中的 application.properties
或 application.yml
,以匹配你生成的证书和主机名:
- 确保
Common Name (CN)
和你连接的主机名一致。 - 如果使用
localhost
作为主机名,证书的CN
也应该为localhost
。
例如:
properties
spring.datasource.url=jdbc:kingbase8://localhost:54321/your_database_name?sslmode=require&ssl=true&sslrootcert=D:/card/server.crt&sslkey=D:/card/server.key
其他注意事项
- 如果是生产环境,建议使用受信任的证书颁发机构(CA)生成的证书,而不是自签名证书。
- 对于生产环境,请确保证书的安全性,并且证书的主机名和数据库连接使用的主机名是一致的。
如何使用 SAN 来支持多个 IP 地址
在 SSL 证书中,Common Name (CN)
只能填写一个值,通常是主机名或者域名,不能填写多个 IP 地址。然而,为了支持多个主机名或 IP 地址,你可以使用 Subject Alternative Name (SAN) 扩展字段,这也是当前更推荐的做法。SAN 允许你在证书中为多个域名或 IP 地址提供额外的标识,使证书能够匹配多个地址。
你可以在生成证书时,将多个 IP 地址添加到 SAN 中。具体步骤如下:
步骤 1:创建一个 OpenSSL 配置文件
首先,创建一个自定义的 OpenSSL 配置文件,例如 openssl.cnf
,并添加 SAN 字段。下面是一个示例配置:
ini
[ req ]
default_bits = 2048
default_md = sha256
distinguished_name = req_distinguished_name
req_extensions = req_ext
prompt = no
[ req_distinguished_name ]
C = CN
ST = YourState
L = YourCity
O = YourOrganization
CN = localhost
[ req_ext ]
subjectAltName = @alt_names
[ alt_names ]
IP.1 = 127.0.0.1
IP.2 = 192.168.1.100
IP.3 = 10.0.0.1
[ req ]
部分定义了一些基础信息,包括使用的加密位数(2048)和消息摘要算法(sha256)。[ req_distinguished_name ]
部分定义证书的基本信息,例如国家、省份、城市、组织和CN
,CN
可以是一个主机名或者 IP。[ req_ext ]
部分定义了证书请求的扩展信息,这里我们通过subjectAltName
来指定多个 IP。[ alt_names ]
是实际的SAN
配置,其中IP.1
、IP.2
等定义了多个 IP 地址。
步骤 2:生成服务器私钥
bash
openssl genrsa -out server.key 2048
步骤 3:生成证书签名请求(CSR)
使用自定义的 OpenSSL 配置文件生成 CSR:
bash
openssl req -new -key server.key -out server.csr -config openssl.cnf
步骤 4:生成自签名证书
使用生成的 CSR 文件和私钥生成自签名证书,证书有效期为 365 天:
bash
openssl x509 -req -in server.csr -signkey server.key -out server.crt -days 365 -extensions req_ext -extfile openssl.cnf
证书中的 SAN 配置
这样生成的证书将包含 Subject Alternative Name
,并支持多个 IP 地址。如果客户端连接时使用证书中的任意一个 IP 地址,SSL 验证应该都能够成功。
验证证书中的 SAN
你可以使用以下命令验证生成的证书是否包含正确的 SAN 信息:
bash
openssl x509 -in server.crt -text -noout
在输出中你应该能够看到 Subject Alternative Name
部分,列出了多个 IP 地址。
Spring Boot 配置
生成证书后,Spring Boot 的配置依然与之前相同,只需确保 sslrootcert
和 sslkey
指向正确的路径即可。
properties
spring.datasource.url=jdbc:kingbase8://127.0.0.1:54321/your_database_name?sslmode=require&ssl=true&sslrootcert=D:/card/server.crt&sslkey=D:/card/server.key
通过使用 SAN 你可以为证书绑定多个 IP 地址,这样无论是通过 127.0.0.1
、192.168.1.100
还是 10.0.0.1
,SSL 都会成功验证。
确认SSL连接
要在 Spring Boot 客户端确认连接是通过 SSL 建立的,而不是普通的非加密连接,可以从以下几种方法进行验证:
1. 查看客户端 SSL 配置及日志
最直接的方法是查看 Spring Boot 启动时的日志。启用 SSL 连接后,JDBC 驱动通常会输出连接的相关信息。你可以增加日志级别来捕获 SSL 连接的详细信息。
步骤:
- 在
application.properties
中启用详细的数据库日志:
properties
logging.level.org.springframework.jdbc=DEBUG
logging.level.com.kingbase8=DEBUG
- 启动 Spring Boot 应用,查看日志输出。如果 SSL 连接成功建立,日志中应有类似以下的信息:
text
DEBUG com.kingbase8.Driver - Establishing SSL connection
DEBUG com.kingbase8.ssl.MakeSSL - SSL connection established
这些日志会确认 SSL 连接是否成功建立。
2. 通过数据库查询确认 SSL 连接
一些数据库允许通过 SQL 查询查看当前连接是否使用了 SSL。在人大金仓数据库中,使用 pg_stat_ssl
视图可以查询客户端是否通过 SSL 连接到数据库。
步骤:
- 连接到人大金仓数据库,执行以下 SQL 查询:
sql
SELECT * FROM pg_stat_ssl;
这个查询会列出所有当前连接的会话,并包含 SSL 连接的信息,例如:
pid | ssl | version | cipher | bits | clientdn |
---|---|---|---|---|---|
1234 | t | TLSv1.2 | ECDHE-RSA-AES128-GCM-SHA256 | 128 |
ssl = t
表示该连接是通过 SSL 建立的。version
和cipher
列会显示当前使用的 SSL 协议和加密套件。
示例输出:
如果 SSL 连接成功建立,你会看到类似这样的行,ssl
列的值为 t
,表示该连接是通过 SSL 建立的。
3. 使用 SQL 查询 pg_stat_ssl
来验证 SSL 连接
使用 JDBC 查询 pg_stat_ssl
你可以通过 JDBC 连接到数据库,并执行 SELECT * FROM pg_stat_ssl
来检查当前连接是否使用了 SSL:
示例代码:
java
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
public class SSLConnectionCheck {
public static void main(String[] args) {
String jdbcUrl = "jdbc:kingbase8://localhost:54321/demo?sslmode=require";
String username = "your_username";
String password = "your_password";
try (Connection conn = DriverManager.getConnection(jdbcUrl, username, password);
Statement stmt = conn.createStatement()) {
// 检查 SSL 连接状态
ResultSet rs = stmt.executeQuery("SELECT * FROM pg_stat_ssl WHERE pid = pg_backend_pid()");
if (rs.next()) {
boolean isSSL = rs.getBoolean("ssl");
String sslVersion = rs.getString("version");
String cipher = rs.getString("cipher");
if (isSSL) {
System.out.println("SSL connection established.");
System.out.println("SSL version: " + sslVersion);
System.out.println("Cipher suite: " + cipher);
} else {
System.out.println("No SSL connection.");
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
代码说明:
- 该代码通过 JDBC 连接人大金仓数据库,并执行
pg_stat_ssl
查询,检查当前会话是否使用了 SSL 连接。 pg_backend_pid()
获取当前连接的进程 ID,通过查询该进程的 SSL 状态,确认是否启用了 SSL。
4. 检查网络流量
如果你想通过更底层的方式验证连接的安全性,可以使用网络抓包工具(如 Wireshark)来捕获数据库连接的网络流量,检查是否为加密的流量。
步骤:
- 使用 Wireshark 或类似工具捕获从客户端到数据库服务器的流量。
- 如果 SSL 连接建立成功,你应该看到加密的数据包,而不是可读的明文数据包。
5. 使用 SSL 强制验证
如果你想确保 SSL 连接的安全性,你可以在 application.properties
中强制使用 sslmode=verify-full
,并确保客户端验证服务器的证书:
properties
spring.datasource.url=jdbc:kingbase8://localhost:54321/demo?sslmode=verify-full&ssl=true&sslrootcert=D:/card/server.crt
这样,如果 SSL 连接未成功建立,客户端将拒绝连接,这也是一种验证 SSL 连接是否建立的间接方式。
总结
- 使用日志查看数据库连接过程中的 SSL 连接信息。
- 通过 SQL 查询
pg_stat_ssl
验证数据库当前会话是否通过 SSL 连接。 - 编写 Java 代码来捕获 SSL 会话的详细信息。
- 使用网络抓包工具确认流量是否加密。