在之前的 nextcloud-fpm + frp + nginx + ssl 一文中,公网服务器的Nginx与家中服务器的Nginx通信是是使用自签名证书的。这样做主要的原因是家中的服务器没有公网IP,无法直接获取公共CA签名的证书;而定时从服务器复制证书下来的操作非常不方便,不值得。但是自签名证书容易被中间人攻击是广为人知的,而为了解决这个问题,今天无意间看到client authentication。大概意思是,传统的HTTPS是客户端验证服务器证书是否有效,而client authentication顾名思义就是加多了服务器验证客户端证书是否有效这一方向,所以也称为双向验证。理论上来说这可以提高安全性,不管怎么说,折腾一下总没错的。
本文会介绍:
- 自签名CA及自签名证书
- 双向证书验证(Nginx)
1. 自签名CA及自签名证书
生成CA及自签名证书需要分开来做。
1.1 CA
生成自己的CA的Key和Cert,会提示设置私钥密码:
1 2
| # 生成10年有效的rsa 2048位CA证书(rootCA.crt)与私钥(rootCA.key) openssl req -x509 -sha256 -days 3650 -newkey rsa:2048 -keyout rootCA.key -out rootCA.crt
|
1.2 Server证书与Client证书
先生成证书私钥和CSR。生成CSR的过程中会提示输入相关信息,其中的Common Name通常是填完整域名——比如买了 somedomain.com
,如果是给子域名 blog.somedomain.com
发证书,Common Name写的就是 blog.somedomain.com
而不是 somedomain.com
。
1 2 3 4 5 6 7
| # 把example.domain.com替换成你自己的域名 # 生成私钥 openssl genrsa -out example.domain.com.server.key 2048 openssl genrsa -out example.domain.com.client.key 2048 # 生成CSR openssl req -new -key example.domain.com.server.key -out example.domain.com.server.csr openssl req -new -key example.domain.com.client.key -out example.domain.com.client.csr
|
然后要创建一个域名附加信息文件domain.ext,内容如下:
1 2 3 4 5
| authorityKeyIdentifier=keyid,issuer basicConstraints=CA:FALSE subjectAltName = @alt_names [alt_names] DNS.1 = example.domain.com
|
然后就可以用CA签发证书了:
1 2
| openssl x509 -req -CA rootCA.crt -CAkey rootCA.key -in example.domain.com.server.csr -out example.domain.com.server.crt -days 3650 -CAcreateserial -extfile domain.ext openssl x509 -req -CA rootCA.crt -CAkey rootCA.key -in example.domain.com.client.csr -out example.domain.com.client.crt -days 3650 -CAcreateserial -extfile domain.ext
|
此时手上应有3对共6个文件:
- Server的Cert和Key
- Client的Cert和Key
- CA的Cert和Key
接下来就要分发了。
2. 设置Nginx
2.1 公网服务器用Client套
把Client的一套( example.domain.com.client.crt
和 example.domain.com.client.key
)以及CA的Cert( rootCA.crt
)上传到公网服务器的Nginx配置文件夹里,比如 /etc/nginx/ssl
。然后修改nextcloud的站点配置文件,主要是把 location /
的proxy指令们增改一下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| server { location / { proxy_ssl_server_name on; proxy_ssl_name $host; proxy_pass https://127.0.0.1:8002/; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Referrer-Policy "no-referrer"; proxy_set_header X-Content-Type-Options "nosniff"; proxy_set_header X-Download-Options "noopen"; proxy_set_header X-Frame-Options "SAMEORIGIN"; proxy_set_header X-Permitted-Cross-Domain-Policies "none"; proxy_set_header X-Robots-Tag "noindex, nofollow"; proxy_set_header X-XSS-Protection "1; mode=block"; proxy_set_header Host $http_host; proxy_set_header cookie $http_cookie; proxy_set_header Proxy-Connection ""; proxy_ssl_certificate /etc/nginx/ssl/example.domain.com.client.crt; proxy_ssl_certificate_key /etc/nginx/ssl/example.domain.com.client.key; proxy_ssl_trusted_certificate /etc/nginx/ssl/rootCA.crt;
proxy_http_version 1.1; } }
|
2.2 家里服务器用Server套
把Server的一套( example.domain.com.server.crt
和 example.domain.com.server.key
)以及Client的Cert( example.domain.com.client.crt
)、CA的Cert( rootCA.crt
)上传到家里服务器的Nginx配置文件夹里,比如 /etc/nginx/ssl
。然后修改nextcloud的站点配置文件,主要是把server blog的ssl指令们增改一下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| server {
ssl_certificate /etc/nginx/ssl/example.domain.com.server.crt; ssl_certificate_key /etc/nginx/ssl/example.domain.com.server.key; ssl_client_certificate /etc/nginx/ssl/example.domain.com.client.key; ssl_trusted_certificate /etc/nginx/ssl/rootCA.crt; ssl_verify_client on;
}
|
注意 ssl_client_certificate
指令是指定client的证书的,就是前面放到公网服务器上用于proxy_ssl_certificate指令的证书。
此时对公网服务器和家里服务器都reload一下Nginx,就应该可以正常访问的了。
参考文章
- CA: 自签名ssl证书生成、 Creating a Self-Signed Certificate With OpenSSL
- Nginx配置文档: proxy_ssl_certificate、 ssl_client_certificate