目的
- 搭建一个Web服务器;
- 配置https访问,并且支持双向认证访问,即客户端和服务器端均需要提供证书访问;
- 所有的证书需要使用国密算法;
实验过程
Ubuntu安装Nginx
1 | sudo apt install nginx |
Nginx相关命令
- 启动
sudo systemctl start nginx
- 关闭
sudo systemctl stop nginx
- 重启
sudo systemctl restart nginx
- 启动
设置防火墙,保证局域网可以访问该web服务器
1
2
3
4sudo ufw app list
sudo ufw allow 'Nginx HTTP'
sudo ufw allow 'Nginx HTTPS'
sudo ufw status局域网下另一台机器可以进行访问
HTTPS双向认证分析
HTTPS单向认证流程
单向认证流程中,服务器端保存着公钥证书和私钥两个文件,整个握手过程如下:
- 客户端发起建立HTTPS连接请求,将SSL协议版本的信息发送给服务器端;
- 服务器端将本机的公钥证书server.crt发送给客户端;
- 客户端读取公钥证书server.crt,取出了服务端公钥;
- 客户端生成一个随机数密钥R,用刚才得到的服务器公钥去加密这个随机数形成密文,发送给服务端;
- 服务端用自己的私钥server.key去解密这个密文,得到了密钥R;
- 服务端和客户端在后续通讯过程中就使用这个密钥R进行通信;
HTTPS双向认证流程
双认证流程握手过程如下:
- 客户端发起建立HTTPS连接请求,将SSL协议版本的信息发送给服务端;
- 服务器端将本机的公钥证书server.crt发送给客户端;
- 客户端读取公钥证书server.crt,取出了服务端公钥;
- 客户端将客户端公钥证书client.crt发送给服务器端;
- 服务器端解密客户端公钥证书,拿到客户端公钥;
- 客户端发送自己支持的加密方案给服务器端;
- 服务器端根据自己和客户端的能力,选择一个双方都能接受的加密方案,使用客户端的公钥加密后发送给客户端;
- 客户端使用自己的私钥解密加密方案,生成一个随机数R,使用服务器公钥加密后传给服务器端;
- 服务端用自己的私钥去解密这个密文,得到了密钥R;
- 服务端和客户端在后续通讯过程中就使用这个密钥R进行通信;
利用国密生成证书
如果要把整个双向认证的流程跑通,最终需要4个证书文件:
- 服务器端公钥证书:server.crt
- 服务器端私钥文件:server.key
- 客户端公钥证书:client.crt
- 客户端私钥文件:client.key
生成这一系列证书之前,需要先生成一个CA根证书,然后由这个CA根证书颁发服务器公钥证书和客户端公钥证书;
全程使用GmSSL来生成一系列的自签名证书,自签名证书没有经过证书机构的认证,很多浏览器会认为不安全,但用来实验是足够的。
安装GmSSL
下载源代码并解压
1
sudo unzip GmSSL-master.zip
编译安装
1
2
3./config no-saf no-sdf no-skf no-sof no-zuc
sudo make
sudo make install执行
gmssl
命令行工具检查安装成功1
gmssl version
生成自签名根证书
1 | sudo mkdir /etc/nginx/keys/ |
经过上面的命令,可以得到一个签名有效期为10年的根证书root.crt,后续用这个根证书去颁发服务器证书和客户端证书。
证书中的pub与root.key是一致的,这样输出的root.crt中,包含了会话的公钥,用于分发加密。而最后的sm3的数字签名,用于通过上面的公钥来验证证书的完整性。
生成自签名服务器端证书
1 | # 利用SM2生成服务器端证书私钥 |
经过上面命令得到:
- server.key:服务器端的秘钥文件
- server.crt:有效期十年的服务器端公钥证书(使用根证书和服务器端私钥文件一起生成)
生成自签名客户端证书
1 | # 利用SM2生成客户端证书私钥 |
经过上面的命令得到:
- client.key:客户端的私钥文件
- client.crt:有效期十年的客户端证书(使用根证书和客户端私钥一起生成)
Nginx配置
创建Nginx配置文件
1
2cd /etc/nginx/sites-enabled
vim https.conf配置文件如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15server {
listen 443 ssl;
server_name 192.168.1.4;
ssl on;
ssl_certificate /etc/nginx/keys/server.crt;#配置证书位置
ssl_certificate_key /etc/nginx/keys/server.key;#配置秘钥位置
ssl_client_certificate /etc/nginx/keys/client.crt;#双向认证
ssl_verify_client on; #双向认证
ssl_session_timeout 5m;
root html;
index index.html;
location / {
try_files $uri $uri/ =404;
}
}重载配置
1
nginx -s reload
验证
- 使用同一局域网下的另一台机器访问该nginx服务器https://192.168.1.4/;
显示如下,需要提供证书才能访问
将密钥复制到另一个文件夹下,使用curl进行验证
1
2
3cp -r /etc/nginx/keys/ /tmp/
cd /tmp/keys/
curl --cert ./client.crt --key ./client.key https://192.168.1.4/ -k -v服务器端与客户端的握手流程如下:
数据包相关参数如下图:
返回的网页源代码如下,可以正常访问,说明双向认证的Web服务器搭建成功。