如果你从上级或者其他人又或者证书提供商那里申请到ssl证书, 要如何才能解锁更多姿势呢? (1) 直接配置在项目上面 (2) 配置在项目启动所依赖的tomcat上 (3) 配置在nginx上( 单向认证, 双向认证, 多域名认证) … … 而这里则主要介绍了两种配置方式, 第一种是在项目中直接配置, 另一种就是通过nginx来进行配置
SSL协议既用到了对称加密也用到了非对称加密(公钥加密),在建立传输链路时,SSL首先使用非对称加密来对对称加密的密钥使用公钥,链路建立好之后,SSL对传输内容使用对称加密。
具体操作步骤如下
将证书放到项目的根目录下(便于后续的引用) 直接ctrl+c 复制证书, ctrl+v 到项目根目录
testone
下, 如下图
server.port=443
#你生成的证书名字
server.ssl.key-store=tomcat.keystore
#密钥库密码
server.ssl.key-store-password=12345678
server.ssl.keyStoreType=JKS
#如果是申请的证书, 则该别名一般是证书绑定的域名 eg:baidu.com
server.ssl.keyAlias:tomcat
这些方法的大致作用是监听当前http访问的端口重定向到https访问的端口(默认为443) spingboot 2.x和springboot 1.x 有些差距, 下面将2.x和1.x单独分开展示
// springboot2 写法
@Bean
public TomcatServletWebServerFactory servletContainer() {
TomcatServletWebServerFactory tomcat = new TomcatServletWebServerFactory() {
@Override
protected void postProcessContext(Context context) {
SecurityConstraint constraint = new SecurityConstraint();
constraint.setUserConstraint("CONFIDENTIAL");
SecurityCollection collection = new SecurityCollection();
collection.addPattern("/*");
constraint.addCollection(collection);
context.addConstraint(constraint);
}
};
tomcat.addAdditionalTomcatConnectors(httpConnector());
return tomcat;
}
@Bean
public Connector httpConnector() {
Connector connector = new Connector("org.apache.coyote.http11.Http11NioProtocol");
connector.setScheme("http");
//监听http的端口号
connector.setPort(8080);
connector.setSecure(false);
//监听到http的端口号后转向到的https的端口号
System.out.println("监听到了80端口");
connector.setRedirectPort(443);//这里的端口写成和配置文件一样的端口就Ok
return connector;
}
@Bean
public EmbeddedServletContainerFactory servletContainer(){
TomcatEmbeddedServletContainerFactory tomcat=new TomcatEmbeddedServletContainerFactory(){
@Override
protected void postProcessContext(Context context) {
SecurityConstraint securityConstraint=new SecurityConstraint();
securityConstraint.setUserConstraint("CONFIDENTIAL");//confidential
SecurityCollection collection=new SecurityCollection();
collection.addPattern("/*");
securityConstraint.addCollection(collection);
context.addConstraint(securityConstraint);
}
};
tomcat.addAdditionalTomcatConnectors(httpConnector());
return tomcat;
}
@Bean
public Connector httpConnector(){
Connector connector=new Connector("org.apache.coyote.http11.Http11NioProtocol");
connector.setScheme("http");
connector.setPort(8080);
connector.setSecure(false);
connector.setRedirectPort(8443);
return connector;
}
}
ps: 如果项目启动后, 仍出现
IOException: Alias name tomcat does not identify a key entry
说明证书的别名(server.ssl.keyAlias
)仍出现问题, 首先需要我们查看下证书的别名, 通过执行下面命令, 倒数第二行第一个字符串即为证书别名
[root@docker01 test]# keytool -keystore 证书名称(需要在证书所在的位置运行) -list
Enter keystore password:
Keystore type: jks
Keystore provider: SUN
Your keystore contains 1 entry
baidu.com, Mar 3, 2021, PrivateKeyEntry, # 注意这里第一个字符串就是正式别名
Certificate fingerprint (SHA1): D0:65:EB:AD:FB:66:A0:9E:94:0D:EC:D0:55:5F:1E:6A:59:FB:BD:84
访问测试
# 通过https访问可以访问成功
https://localhost/test/123
# 项目原本端口配置的是8080, 但在上面配置好证书以后, 如果通过http则会提示错误请求
http://localhost:8080/test/123
https单向认证的流程大致如下:
注意:
# 安装依赖库
yum -y install gcc gcc-c++ automake pcre pcre-devel zlib zlib-devel openssl openssl-devel
# 下载安装包
wget http://nginx.org/download/nginx-1.16.1.tar.gz
# 解压文件
tar zxvf nginx-1.16.1.tar.gz
# 改名
mv nginx-1.16.1 nginx
# 移动到/usr/local下
rm nginx nginx-1.16.1.tar.gz -f
# 进入
cd /usr/local/nginx
# 配置ssl模块
./configure --user=nginx --prefix=/usr/local/nginx --with-http_ssl_module
# 安装配置
make & make install
# 创建 logs目录
mkdir logs
# 注意; 启动文件在 /objs 目录下
./nginx
直接执行下面命令, 复制后直接全部执行, 但是需要注意自己nginx所在位置以及 localhost 所在位置(改为自己的ip或者域名)
openssl genrsa -out /usr/local/nginx/conf/server.key 2048
openssl req -new -key /usr/local/nginx/conf/server.key -out /usr/local/nginx/conf/server.csr<<EOF
CN
JS
NJ
Hrt
OPS
localhost
EOF
openssl x509 -req -days 36500 -in /usr/local/nginx/conf/server.csr -signkey /usr/local/nginx/conf/server.key -out /usr/local/nginx/conf/server.crt
注意: CN,JS…相当与下图生成签证时填写的信息
需要根据注意事项来修改配置文件
注意
mkdir logs
ssl_certificate ,ssl_certificate_key
配置证书公钥和私钥所在地址location /
的反向代理配置user nginx nginx;
#下面两行按照实际配置
#worker_processes 8;
#worker_cpu_affinity 0001 0010 0100 1000 0001 0010 0100 1000;
pid logs/nginx.pid;
worker_rlimit_nofile 204800;
events {
worker_connections 204800;
use epoll;
}
http {
include mime.types;
default_type application/octet-stream;
log_format main '{"@timestamp":"$time_iso8601",'
'"@source":"$server_addr",'
'"hostname":"$hostname",'
'"ip":"$http_x_forwarded_for",'
'"client":"$remote_addr",'
'"request_method":"$request_method",'
'"scheme":"$scheme",'
'"domain":"$server_name",'
'"referer":"$http_referer",'
'"request":"$request_uri",'
'"args":"$args",'
'"request_body":"$request_body",'
'"size":$body_bytes_sent,'
'"@status": $status,'
'"responsetime":$request_time,'
'"upstreamtime":"$upstream_response_time",'
'"upstreamaddr":"$upstream_addr",'
'"http_user_agent":"$http_user_agent",'
'"https":"$https"'
'}';
access_log /usr/local/nginx/logs/access.log main;
sendfile on;
tcp_nopush on;
open_file_cache max=204800 inactive=20s;
open_file_cache_min_uses 1;
open_file_cache_valid 40s;
geo $whiteiplist {
default 1;
#192.168.158.188 0;
#192.168.158.189 0;
}
map $whiteiplist $limit {
1 $binary_remote_addr;
0 "";
}
limit_req_zone $limit zone=rateip:100m rate=1000r/s;
limit_conn_zone $limit zone=perip:100m;
autoindex off;
server_tokens off;
#keepalive_timeout 0;
max_ranges 1;
keepalive_timeout 65;
send_timeout 120;
proxy_read_timeout 120;
proxy_connect_timeout 120;
client_max_body_size 512m;
client_header_timeout 60;
client_body_timeout 60;
server_names_hash_bucket_size 64;
#gzip on;
gzip on;
gzip_min_length 1k;
gzip_buffers 4 16k;
gzip_http_version 1.0;
gzip_comp_level 2;
gzip_types text/plain application/x-javascript text/css application/xml text/javascript application/javascript image/jpeg image/gif image/png;
gzip_vary on;
client_body_buffer_size 1024k;
client_header_buffer_size 1024k;
large_client_header_buffers 4 4096k;
proxy_send_timeout 1m;
proxy_buffer_size 16k;
proxy_buffers 4 64k;
proxy_busy_buffers_size 128k;
proxy_temp_file_write_size 128k;
proxy_temp_path /usr/local/nginx/proxy_temp;
proxy_cache_path /usr/local/nginx/proxy_cache levels=1:2 keys_zone=content:20m inactive=1d max_size=100m;
#add https
server {
listen 443 ssl;
#server_name api.clife.cn;
server_name localhost;
root /usr/local/nginx/html;
access_log /usr/local/nginx/logs/https_access.log main;
limit_conn perip 1000;
limit_req zone=rateip burst=100 nodelay;
ssl on;
ssl_certificate /usr/local/nginx/conf/server.crt;
ssl_certificate_key /usr/local/nginx/conf/server.key;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; #按照这个协议配置
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE;#按照这个套件配置
ssl_session_cache shared:SSL:1m;
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:1m;
ssl_session_timeout 5m;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header REMOTE-HOST $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Request-URI $scheme://$host$uri;
# if ($http_user_agent ~* "WMSDK")
# { return 404; }
if ($http_user_agent ~* "echo|uname|concat|select|bash|nmap|scan" ) {
return 403;
}
location ~* \.(bak|save|sh|sql|mdb|old)$ {
rewrite ^/(.*)$ $host permanent;
}
if ($query_string ~* "union.*select.*\(") {
rewrite ^/(.*)$ $host permanent;
}
if ($query_string ~* "concat.*\(") {
rewrite ^/(.*)$ $host permanent;
}
# 这里反向代理作用是: 当在浏览器输入 https://ip/ 的时候相当于访问了http://ip:8083, 可根据需要自行配置
location / {
proxy_pass http://ip:8083;
}
}
}
双向认证大致流程为
注意:
我们可以全程使用openssl来生成一些列的自签名证书,自签名证书没有通过证书机构的认证, 虽然很多浏览器会认为不安全,但我们用来实验是足够的。 需要安装的nginx版本在1.6.1且支持ssl 模块(见第二章第1节)
由上图梳理证书创建流程: 创建根证书 -> 根据根证书创建服务端证书 -> 根据根证书创建客户端证书
#(1)创建根证书私钥:
openssl genrsa -out root.key 1024
#(2)创建根证书请求文件:
openssl req -new -out root.csr -key root.key
#后续参数请自行填写,下面是一个例子:
Country Name (2 letter code) [XX]:cn
State or Province Name (full name) []:jiangsu
Locality Name (eg, city) [Default City]:nanjing
Organization Name (eg, company) [Default Company Ltd]:hrt
Organizational Unit Name (eg, section) []:njhrt
Common Name (eg, your name or your servers hostname) []:root
Email Address []: # 直接回车即可
A challenge password []: # 直接回车即可
An optional company name []: # 直接回车即可
#(3)创建根证书:
openssl x509 -req -in root.csr -out root.crt -signkey root.key -CAcreateserial -days 3650
在创建根证书和下面服务器请求文件和客户端请求文件的时候需要注意:
经过上面三个命令, 我们可以得到
后面我们可以用这个根证书去颁发服务器证书和客户端证书
#(1)生成服务器端证书私钥:
openssl genrsa -out server.key 1024
#(2) 生成服务器证书请求文件,过程和注意事项参考根证书,本节不详述:
openssl req -new -out server.csr -key server.key
#(3) 生成服务器端公钥证书
openssl x509 -req -in server.csr -out server.crt -signkey server.key -CA root.crt -CAkey root.key -CAcreateserial -days 3650
通过上面的三个命令,我们得到:
需要注意的是, 可以生成多个客户端证书, 只需安装下面1-4步重新生成即可
#(1)生成客户端证书秘钥:
openssl genrsa -out client.key 1024
#(2) 生成客户端证书请求文件,过程和注意事项参考根证书,本节不详述:
openssl req -new -out client.csr -key client.key
#(3) 生客户端证书
openssl x509 -req -in client.csr -out client.crt -signkey client.key -CA root.crt -CAkey root.key -CAcreateserial -days 3650
#(4) 生客户端p12格式证书,需要输入一个密码,选一个好记的,比如123456
openssl pkcs12 -export -clcerts -in client.crt -inkey client.key -out client.p12
重复使用上面的三个命令,我们得到:
server {
listen 443 ssl;
server_name www.yourdomain.com;# 无域名可填写ip
ssl on;
ssl_certificate /data/sslKey/server.crt; #server公钥证书
ssl_certificate_key /data/sslKey/server.key; #server私钥
ssl_client_certificate /data/sslKey/root.crt; #根证书,可以验证所有它颁发的客户端证书
ssl_verify_client on; #开启客户端证书验证
# 反向代理eg: 作用是通过https(443端口)访问, 则会直接去请求本机的8991端口
location / {
proxy_pass http://127.0.0.1:8991/;
}
#location / {
# root html;
# index index.html index.htm;
# }
}
注意:
nginx -s reload
令配置文件重新加载, 无需重启
进入 File -> Settings
400 No required SSL certificate was sent
, 提示客户端没有提供所需的证书
在配置好客户端证书之后, 发现可以正常访问
浏览器一般用单向认证会比较多,双向认证的详细配置步骤这里就不多说了。 主要就是把自己客户端的证书文件(.p12, crt)双击之后安装到自己电脑的证书列表中再访问服务端, 如果提示服务端的证书有风险,点击继续就行。需要注意的是, 如果之前访问不成功, 在安装好证书之后需要重启浏览器才会生效
访问成功效果如下图所示:
关于更多证SSL书文档配置可见下面参考文档, 后续也会在此基础上继续更新…
参考文档 1. springboot项目配置阿里云ssl证书,http转https 2. Springboot配置使用ssl,使用https 3. Spring boot使用阿里云SSL证书报错:org/springframework/boot/context/properties/bind/Binder 4. IOException: Alias name tomcat does not identify a key entry 沃通证书部署问题解决办法