在前面一篇文章中我们已经大概了解为了防止数据在传输中不被其他人看见,我们可以对数据进行加密,并使用CA证书进一步提高了安全性,接下来本篇文章将展示如何自建证书应用到web项目中以及常见的http转https的方法。
1. 使用JDK的keytool工具
我们可以使用JDk的keytool工具来完成密钥对和证书的创建。keytool工具使用keystore文件来存储密钥和证书(存储在服务端的公钥和私钥,证书上的公钥)
PS E:\program\java\jdk-17.0.4\bin> .\keytool.exe
密钥和证书管理工具
命令:
-certreq 生成证书请求
-changealias 更改条目的别名
-delete 删除条目
-exportcert 导出证书
-genkeypair 生成密钥对
-genseckey 生成密钥
-gencert 根据证书请求生成证书
-importcert 导入证书或证书链
-importpass 导入口令
-importkeystore 从其他密钥库导入一个或所有条目
-keypasswd 更改条目的密钥口令
-list 列出密钥库中的条目
-printcert 打印证书内容
-printcertreq 打印证书请求的内容
-printcrl 打印 CRL 文件的内容
-storepasswd 更改密钥库的存储口令
-showinfo 显示安全相关信息
使用 "keytool -?, -h, or --help" 可输出此帮助消息
使用 "keytool -command_name --help" 可获取 command_name 的用法。
使用 -conf 选项可指定预配置的选项文件。
1、生成keystore .\keytool.exe -genkeypair -alias test-alias -keypass 123456 -keyalg RSA -validity 365 -keystore f:\ca\test-alias.keystore -storepass 123456 -ext san=dns:localhost
注意不要忘记添加:-ext san=dns:localhost
用于添加域名信息
-storepass 123456
密钥库口令值-keypass 123456
密钥口令值
【详细过程】PS E:\program\java\jdk-17.0.4\bin> .\keytool.exe -genkeypair -alias test-alias -keypass 123456 -keyalg RSA -validity 365 -keystore f:\ca\test-alias.keystore -storepass 123456 -ext san=dns:localhost 您的名字与姓氏是什么? [Unknown]: chen 您的组织单位名称是什么? [Unknown]: chen 您的组织名称是什么? [Unknown]: chen 您所在的城市或区域名称是什么? [Unknown]: Shanghai 您所在的省/市/自治区名称是什么? [Unknown]: Shanghai 该单位的双字母国家/地区代码是什么? [Unknown]: cn CN=chen, OU=chen, O=chen, L=Shanghai, ST=Shanghai, C=cn是否正确? [否]: y 正在为以下对象生成 2,048 位RSA密钥对和自签名证书 (SHA256withRSA) (有效期为 365 天): CN=chen, OU=chen, O=chen, L=Shanghai, ST=Shanghai, C=cn PS E:\program\java\jdk-17.0.4\bin>
2、查看keystore
.\keytool.exe -list -v -keystore f:\ca\test-alias.keystore
【详细过程】PS E:\program\java\jdk-17.0.4\bin> .\keytool.exe -list -v -keystore f:\ca\test-alias.keystore 输入密钥库口令: 密钥库类型: PKCS12 密钥库提供方: SUN 您的密钥库包含 1 个条目 别名: test-alias 创建日期: 2022年12月6日 条目类型: PrivateKeyEntry 证书链长度: 1 证书[1]: 所有者: CN=chen, OU=chen, O=chen, L=Shanghai, ST=Shanghai, C=cn 发布者: CN=chen, OU=chen, O=chen, L=Shanghai, ST=Shanghai, C=cn 序列号: 37780c1e2a0352e5 生效时间: Tue Dec 06 15:31:39 CST 2022, 失效时间: Wed Dec 06 15:31:39 CST 2023 证书指纹: SHA1: 9C:49:38:FF:AA:74:36:60:81:FF:10:88:D3:43:D7:21:21:F9:29:15 SHA256: AE:95:CD:DB:2E:BA:45:B1:EA:66:39:D1:1A:9F:6E:AF:A4:18:A2:CE:C4:8D:B7:F1:AA:D0:52:35:82:0D:03:69 签名算法名称: SHA256withRSA 主体公共密钥算法: 2048 位 RSA 密钥 版本: 3 扩展: #1: ObjectId: 2.5.29.17 Criticality=false SubjectAlternativeName [ DNSName: localhost ] #2: ObjectId: 2.5.29.14 Criticality=false SubjectKeyIdentifier [ KeyIdentifier [ 0000: D4 ED F5 3C F5 3B F8 74 93 6C 9C 1F B9 2E AD 73 ...<.;.t.l.....s 0010: 3E 1C 1D B4 >... ] ] ******************************************* *******************************************
或者
.\keytool.exe -list -rfc -keystore f:\ca\test-alias.keystore
【详细过程】
PS E:\program\java\jdk-17.0.4\bin> .\keytool.exe -list -rfc -keystore f:\ca\test-alias.keystore
输入密钥库口令:
密钥库类型: PKCS12
密钥库提供方: SUN
您的密钥库包含 1 个条目
别名: test-alias
创建日期: 2022年12月6日
条目类型: PrivateKeyEntry
证书链长度: 1
证书[1]:
-----BEGIN CERTIFICATE-----
MIIDeTCCAmGgAwIBAgIIN3gMHioDUuUwDQYJKoZIhvcNAQELBQAwYDELMAkGA1UE
BhMCY24xETAPBgNVBAgTCFNoYW5naGFpMREwDwYDVQQHEwhTaGFuZ2hhaTENMAsG
A1UEChMEY2hlbjENMAsGA1UECxMEY2hlbjENMAsGA1UEAxMEY2hlbjAeFw0yMjEy
MDYwNzMxMzlaFw0yMzEyMDYwNzMxMzlaMGAxCzAJBgNVBAYTAmNuMREwDwYDVQQI
EwhTaGFuZ2hhaTERMA8GA1UEBxMIU2hhbmdoYWkxDTALBgNVBAoTBGNoZW4xDTAL
BgNVBAsTBGNoZW4xDTALBgNVBAMTBGNoZW4wggEiMA0GCSqGSIb3DQEBAQUAA4IB
DwAwggEKAoIBAQCa/sa0kFetjFI7xqokGKp/ahzmqAYuzcpxfjM//xmZliwwZ7Fu
7uquSyT/T9k0R40+tWieXT6yHfnOZhsfhpz0KgR/k6AUdzOb3ThE87+gDDdZ0kTy
8FY8glpUXbgj+O1Ljcfi+7dbUZlxvoB5wU2jnj5sNFp+/RUc8hCDX8DVzbx1IFnZ
Kebscb8Exa9JBnYENyLMBd6MUNETnAQK1qVbsUTQ2kZQWbyLMJzUgDLwH64QBY3c
qsPmbUDn32/q2NjG8aAyBC3v3Lx7+BnPCQ2REWX92E4Lijhh2vPimRSFl5P/zuQ8
xBr6TidiQoPEo1/lwpsQCA0rhAsPjMPqJ7TlAgMBAAGjNzA1MB0GA1UdDgQWBBTU
7fU89Tv4dJNsnB+5Lq1zPhwdtDAUBgNVHREEDTALgglsb2NhbGhvc3QwDQYJKoZI
hvcNAQELBQADggEBAAgtODXsx+sSkuudfnPqhcM3u3OcQMuG4Ut25LwfZzKoF7zo
gsQvNySQ6Ea8Bcu9yXL2iH5m9kMnDkLR5tjI4hKg3DgpIjdCINCrBRDJxn+jYrnG
z+vvXx6PlqcYo4ogoRyI1gomLK/HnrQEb70EQCQwj3Ia0WAn+YM90Mczz6t+/jBk
vKjcm5KmKxuZabM0/Vb5VHCEW3B2/SjCt+q3mob6qpMKPvjPGVQDNLIBNK421h3S
GHiomwNB0kYibJkJCalM4MiX7mF+7IsycYPijmNfMHaLtYOJkDLuFp1bLxaMIzTa
zeRSCsuLUoOk1ZxiZoQAzavXPoB7Tr0mC/EFv2g=
-----END CERTIFICATE-----
*******************************************
*******************************************
3、导出证书 .\keytool.exe -exportcert -alias test-alias -keystore f:\ca\test-alias.keystore -file f:\ca\my.cer
【详细过程】
PS E:\program\java\jdk-17.0.4\bin> .\keytool.exe -exportcert -alias test-alias -keystore f:\ca\test-alias.keystore -file f:\ca\my.cer
输入密钥库口令:
存储在文件 中的证书
2. 在web中使用
1、创建一个SpringBoot项目,添加测试接口
@RestController
public class TestController {
@GetMapping("/hello")
public String hello() {
return "hello https";
}
}
2、启动项目
- 访问:
http://localhost:8004/hello
没问题 - 访问:
https://localhost:8004/hello
访问失败 ssl协议不支持
3、接下来我们把前面生成的test-alias.keystore
文件拷贝到resource目录下,并完成如下配置
server:
port: 8004
ssl:
key-alias: test-alias
key-store: classpath:test-alias.keystore
key-store-type: JKS
key-store-password: 123456
key-password: 123456
4、访问
- 访问
http://localhost:8004/hello
出错 访问:
https://localhost:8004/hello
显示我们的连接不是私密连接
直接点进去,正常:解决提示不安全
在前面的测试访问中,服务端配置了密钥和证书之后,访问会提示不安全,之所以出现这种提示,是因为浏览器还没有安装我们生成的证书,接下来我们就把前面生成的证书安装。
打开浏览器,查看证书已经按照好:
再次访问https://localhost:8004/hello (如何有问题 试试清理浏览器缓存)
http转https 简单办法
当希望用户没有指定https来访问时也调整到https访问,我们可以添加如下配置:
1、在application.yml
中添加http端口为82
http-port: 82
server:
port: 8004
ssl:
key-alias: test-alias
key-store: classpath:test-alias.keystore
key-store-type: JKS
key-store-password: 123456
key-password: 123456
2、添加配置
@Configuration
public class HttpToHttps {
// https的端口
@Value("${server.port}")
private int sslPort;
// http的端口
@Value("${http-port}")
private int httpPort;
@Bean
public TomcatServletWebServerFactory servletContainerFactory() {
TomcatServletWebServerFactory tomcat = new TomcatServletWebServerFactory() {
@Override
protected void postProcessContext(Context context) {
//设置安全性约束
SecurityConstraint securityConstraint = new SecurityConstraint();
securityConstraint.setUserConstraint("CONFIDENTIAL");
//设置约束条件
SecurityCollection collection = new SecurityCollection();
//拦截所有请求
collection.addPattern("/*");
securityConstraint.addCollection(collection);
context.addConstraint(securityConstraint);
}
};
Connector connector = new Connector("org.apache.coyote.http11.Http11NioProtocol");
//遇到http进行转发
connector.setScheme("http");
//true: http使用http, https使用https;
//false: http重定向到https;
connector.setSecure(false);
// 设置http端口
connector.setPort(httpPort);
//重定向端口号(非SSL到SSL)
connector.setRedirectPort(sslPort);
tomcat.addAdditionalTomcatConnectors(connector);
return tomcat;
}
}
3、测试
当访问http://localhost:82/hello
时发现直击跳转为https://localhost:8004/hello
https转https企业方法
在真实开发中,我们一般使用Nginx来帮助我们完成http转https。
1、使用openssl来完成证书的创建
【详细过程】
PS E:\cer2\nginx> openssl genrsa -des3 -out dongbao.key 1024
Loading 'screen' into random state - done
Generating RSA private key, 1024 bit long modulus
..................++++++
....++++++
e is 65537 (0x10001)
Enter pass phrase for dongbao.key:
Verifying - Enter pass phrase for dongbao.key:
PS E:\cer2\nginx> openssl req -new -key dongbao.key -out dongbao.csr
Enter pass phrase for dongbao.key:
Loading 'screen' into random state - done
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:cn
State or Province Name (full name) [Some-State]:bj
Locality Name (eg, city) []:bj
Organization Name (eg, company) [Internet Widgits Pty Ltd]:msb
Organizational Unit Name (eg, section) []:msb
Common Name (e.g. server FQDN or YOUR name) []:cpf.com
Email Address []:[email protected]
Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:123456
An optional company name []:
PS E:\cer2\nginx> openssl rsa -in .\dongbao.key.src -out dongbao.key
Enter pass phrase for .\dongbao.key.src:
writing RSA key
PS E:\cer2\nginx> openssl x509 -req -days 365 -in .\dongbao.csr -signkey .\dongbao.key -out dongbao.crt
Loading 'screen' into random state - done
Signature ok
subject=/C=cn/ST=bj/L=bj/O=msb/OU=msb/CN=cpf.com/[email protected]
Getting Private key
PS E:\cer2\nginx>
2、配置conf文件
#user nobody;
worker_processes 1;
#error_log logs/error.log;
#error_log logs/error.log notice;
#error_log logs/error.log info;
#pid logs/nginx.pid;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
#log_format main '$remote_addr - $remote_user [$time_local] "$request" '
# '$status $body_bytes_sent "$http_referer" '
# '"$http_user_agent" "$http_x_forwarded_for"';
#access_log logs/access.log main;
sendfile on;
#tcp_nopush on;
#keepalive_timeout 0;
keepalive_timeout 65;
#gzip on;
server {
listen 80;
server_name localhost;
#charset koi8-r;
#access_log logs/host.access.log main;
location / {
root html;
index index.html index.htm;
}
#error_page 404 /404.html;
# redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
# proxy the PHP scripts to Apache listening on 127.0.0.1:80
#
#location ~ \.php$ {
# proxy_pass http://127.0.0.1;
#}
# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
#
#location ~ \.php$ {
# root html;
# fastcgi_pass 127.0.0.1:9000;
# fastcgi_index index.php;
# fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name;
# include fastcgi_params;
#}
# deny access to .htaccess files, if Apache's document root
# concurs with nginx's one
#
#location ~ /\.ht {
# deny all;
#}
}
# another virtual host using mix of IP-, name-, and port-based configuration
#
#server {
# listen 8000;
# listen somename:8080;
# server_name somename alias another.alias;
# location / {
# root html;
# index index.html index.htm;
# }
#}
upstream com.cpf {
server 127.0.0.1:8080; # 需要监听的端口名 我用的
keepalive 64;
}
# HTTPS server
#
server {
listen 443 ssl;
server_name cpf.com;
ssl_certificate E://cer2//nginx//dongbao.crt;
ssl_certificate_key E://cer2//nginx//dongbao.key;
ssl_session_cache shared:SSL:1m;
ssl_session_timeout 5m;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
location / {
proxy_pass http://com.cpf;
}
}
}
3、进行测试和访问同样可以达到效果