Rootop 服务器运维与web架构

2025-06-30
发表者 Venus
nginx配置mTLS双向认证已关闭评论

nginx配置mTLS双向认证

环境 almalinux9.3
openssl版本 3.x

证书生成简化脚本

#!/bin/bash

# 1、生成私钥公钥,自己作为CA机构。
echo "#############################################################################################################"
echo "生成CA证书"
mkdir ca && cd ca
openssl genpkey -algorithm RSA -out ca.key -pkeyopt rsa_keygen_bits:2048
openssl req -new -key ca.key -out ca.csr

cat <<EOF > v3_ca.ext
basicConstraints = critical, CA:TRUE
keyUsage = critical, keyCertSign, cRLSign
subjectKeyIdentifier = hash
EOF

openssl x509 -req -in ca.csr -signkey ca.key -out ca.crt -days 3650 -extfile v3_ca.ext
# 注意这里明确声明自己作为CA,CA:TRUE。
echo "#############################################################################################################"
cd ..
 
 
# 给服务器(域名)颁发证书
echo "#############################################################################################################"
echo "生成域名证书"
mkdir server && cd server
openssl genpkey -algorithm RSA -out server.key -pkeyopt rsa_keygen_bits:2048
openssl req -new -key server.key -out server.csr
 
# 创建一个SAN文件
cat <<EOF > san.conf 
authorityKeyIdentifier=keyid,issuer
basicConstraints=CA:FALSE
keyUsage = digitalSignature, keyEncipherment
extendedKeyUsage = serverAuth
subjectAltName = @alt_names
 
[alt_names]
DNS.1 = www.test.com
DNS.2 = test.x.com
IP.1 = 127.0.0.1
IP.1 = 192.168.6.114
EOF
 
# 用ca的证书给csr颁发证书
openssl x509 -req -in server.csr -CA ../ca/ca.crt -CAkey ../ca/ca.key  -CAcreateserial -out server.crt -days 365 -extfile san.conf
 
 
# 验证证书链
echo "验证证书链"
openssl verify -CAfile ../ca/ca.crt server.crt
#如果输出 server.crt: OK,说明证书链正确。
echo "#############################################################################################################"
 
cd ..

echo "#############################################################################################################"
echo "生成客户端证书"
mkdir client && cd client
openssl genpkey -algorithm RSA -out client.key -pkeyopt rsa_keygen_bits:2048
openssl req -new -key client.key -out client.csr
openssl x509 -req -in client.csr -CA ../ca/ca.crt -CAkey ../ca/ca.key  -CAcreateserial -out client.crt -days 365

echo "#############################################################################################################"
rm -f /home/software/openresty/nginx/conf/vhost/server/*
cp ../server/* /home/software/openresty/nginx/conf/vhost/server/
cp ../ca/ca.crt /home/software/openresty/nginx/conf/vhost/server/
/home/software/openresty/nginx/sbin/nginx -s reload

echo "curl访问"
curl --cert client.crt --key client.key --cacert ../ca/ca.crt https://www.test.com


# 为了将证书导入到浏览器,生成p12格式
openssl pkcs12 -export -inkey client.key -in client.crt -out client.p12 -name "ClientCert"


# nginx配置
server {

	listen	80;
	listen	443 ssl;
	http2 on;
	server_name  www.test.com;
	root /www;
	index index.php index.html;
	
	ssl_certificate /home/software/openresty/nginx/conf/vhost/server/server.crt;
	ssl_certificate_key /home/software/openresty/nginx/conf/vhost/server/server.key;
	
	ssl_session_timeout 5m;
	ssl_protocols TLSv1.1 TLSv1.2;
	ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE;
	ssl_prefer_server_ciphers on;
	
	ssl_verify_client on;
	ssl_client_certificate /home/software/openresty/nginx/conf/vhost/server/ca.crt;
	
	client_max_body_size 100M;
	
	server_tokens off;
	fastcgi_hide_header X-Powered-By;

	location ~ \.php$
	{
		fastcgi_split_path_info ^((?U).+.php)(/?.+)$;
		fastcgi_param  PATH_INFO $fastcgi_path_info;
		fastcgi_param  PATH_TRANSLATED $document_root$fastcgi_path_info;
		fastcgi_pass   127.0.0.1:10000;
		fastcgi_index  index.php;
		fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
		fastcgi_param  RGS_COREPATHNAME GameMotors;
		include        fastcgi_params;
	}

	access_log  /var/log/nginx/www.test.com-access.log;
	error_log   /var/log/nginx/www.test.com-error.log;
}

# ssl_verify_client on 是开启验证客户端证书。
# ssl_client_certificate 这个参数告诉nginx我信任这个文件中的 CA,如果客户端提交的证书是由这些 CA 签发的,那我就接受。

1、首先双击 ca.crt 文件,导入到本地,选择 受信任的根证书颁发机构。这样浏览器才会信任,不会报不安全。
2、Chrome浏览器导入p12证书,点击 设置 – 隐私与安全 – 安全 – 管理证书 – 您的证书 – 管理从Windows导入的证书
点击 导入,选择刚才的p12证书文件。 “证书存储” 部分,选择 “将所有的证书都放入下列存储”,选择 “个人” ,完成。
浏览器访问 https://www.test.com/ 会弹窗选择客户端证书。

如果不导入证书,则访问时nginx会报下面错误

2025-06-19
发表者 Venus
mTLS双向认证已关闭评论

mTLS双向认证

mTLS 通信流程
1 证书准备:
服务端和客户端都拥有各自的 X.509 证书和私钥
证书由同一个受信任的 CA 签发(可以是私有 CA)

2 握手过程(TLS Handshake):
客户端发起连接请求
服务端返回其证书
客户端验证服务端证书(CA 签名 + 域名匹配)
客户端也发送自己的证书
服务端验证客户端证书
双方协商会话密钥 R,建立加密通道

3 通信加密:
所有数据通过协商出的密钥进行加密传输(R为对称加密秘钥,不再使用公钥加密)
双方身份已验证,通信安全可信

公钥加密是为“身份验证 + 密钥协商”服务的,不是为了日常数据传输。真正保护数据的是协商出来的对称密钥 R。

nginx实现方式:

server {
    listen 443 ssl;
    server_name api.example.com;

    ssl_certificate     /etc/nginx/certs/server.crt;
    ssl_certificate_key /etc/nginx/certs/server.key;

    ssl_client_certificate /etc/nginx/certs/ca.crt;
    ssl_verify_client on;  # 强制客户端提供证书

    location / {
        proxy_pass http://backend;
    }
}

参考:https://help.aliyun.com/zh/api-gateway/traditional-api-gateway/user-guide/mutual-tls-authentication

2025-06-19
发表者 Venus
作为CA (Certificate Authority)机构颁发证书已关闭评论

作为CA (Certificate Authority)机构颁发证书

# 1、生成私钥公钥,自己作为ca。
mkdir ca && cd ca
openssl genpkey -algorithm RSA -out ca.key -pkeyopt rsa_keygen_bits:2048
openssl req -new -key ca.key -out ca.csr

cat <<EOF > v3_ca.ext
basicConstraints = critical, CA:TRUE
keyUsage = critical, keyCertSign, cRLSign
subjectKeyIdentifier = hash
EOF
openssl x509 -req -in ca.csr -signkey ca.key -out ca.crt -days 3650 -extfile v3_ca.ext

用自己的私钥给自己签名,颁发者和持有者一样。有效期10年。
有了私钥和证书就可以给其它证书签名请求进行证书签发。
注意在openssl 3.x版本中如果证书中没有声明 basicConstraints = CA:TRUE,则该证书 不能被视为有效的 CA。
之前在centos7中,默认openssl 1.x版本,对证书验证时(openssl verify)不严格检查 basic Constraints
即使缺少 CA:TRUE 也默认为合法 CA(宽松兼容性)。

# 给服务器(域名)颁发证书
# 自己生成私钥和csr,可以自己生成也可以客户端生成
mkdir entain && cd entain
openssl genpkey -algorithm RSA -out server.key -pkeyopt rsa_keygen_bits:2048
openssl req -new -key server.key -out server.csr

# 创建一个SAN文件
[root@docker-server entain]# cat san.conf 
authorityKeyIdentifier=keyid,issuer
basicConstraints=CA:FALSE
keyUsage = digitalSignature, keyEncipherment
extendedKeyUsage = serverAuth
subjectAltName = @alt_names

[alt_names]
DNS.1 = x.com
DNS.2 = entain.x.com
IP.1 = 127.0.0.1


# 用ca的证书给csr颁发证书
openssl x509 -req -in server.csr -CA ../ca/ca.crt -CAkey ../ca/ca.key  -CAcreateserial -out server.crt -days 365 -extfile san.conf


# 验证证书链
检查 server.crt 是否正确签署:
openssl verify -CAfile ../ca/ca.crt server.crt
如果输出 server.crt: OK,说明证书链正确。

windows必须导入 ca.crt 作为受信任的根证书,否则浏览器或系统不会信任服务器证书。



########################################################################################################################################
# 其它补充资料
# 私钥、公钥、证书 三者的关系
为什么 .crt(证书) 不是公钥?
.crt 是完整的证书,里面包含:
公钥(Public Key)
证书信息(如域名、有效期)
CA 的签名(如果是受信任证书)

如果用 OpenSSL 查看 .crt 文件,会发现它不只是公钥:
openssl x509 -in server.crt -text -noout
其中会显示 证书颁发机构(Issuer)、有效期、使用限制 等。

openssl x509 -in server.crt -pubkey -noout > server.pub
这样 server.pub 才是单纯的公钥。


# nginx 加载证书重启报错
SSL: error:0A00018F:SSL routines::ee key too small 表示 SSL/TLS 连接失败。
可能的原因是私钥长度过短,现代 SSL/TLS 需要 至少 2048 位 的 RSA 私钥。
之前没加长度参数,默认是1024

# 查看私钥长度
openssl rsa -in server.key -text -noout | grep "Private-Key"

openssl genpkey -algorithm RSA -out server.key -pkeyopt rsa_keygen_bits:2048   # 后面加上长度,默认1024
genpkey         生成私钥(支持多种算法,包括 RSA、ECDSA、Ed25519)。
-algorithm RSA  指定密钥算法为 RSA。
-out server.key 生成的私钥存储在 server.key 文件中。
-pkeyopt rsa_keygen_bits:2048  指定 RSA 密钥长度为 2048 位。


# 关于 SAN (Subject Alternative Name) 主题备用名称。
它是 X.509 证书扩展字段,用于指定多个域名或IP 地址,使证书能适用于多个网站或服务器。例如:
example.com
www.example.com
sub.example.com
192.168.1.100

如果颁发证书时没有配置SAN信息,Chrome 和 Firefox 会报“证书无效”,哪怕 CN 是正确的。
尤其是在 2020 年后所有现代浏览器都不再信任仅带 CN 的证书。

chrome提示:
此服务器无法证实它就是 x.x.com - 它的安全证书没有指定主题备用名称。这可能是因为某项配置有误或某个攻击者拦截了您的连接。

# 查看证书中的SAN信息
openssl x509 -in server.crt -noout -text
可以看到关于SAN字段的信息
略···
X509v3 Subject Alternative Name: 
	DNS:x.com, DNS:entain.x.com, IP Address:127.0.0.1
略···

通过openssl命令查看了一个Let's Encrypt颁发的证书,其中此字段的值和CN字段值一致。
在实际应用中,直接保持两者一致即可,当然SAN中可以写多个(也就是云平台中卖的 多域名证书)。

2025-06-19
发表者 Venus
自签名证书生成步骤已关闭评论

自签名证书生成步骤

流程分为3步:生成私钥 – 生成CSR – 自己颁发证书

# 1、生成RSA私钥
[root@docker-server cert]# openssl genrsa -out server.key 2048
openssl          OpenSSL工具,用于处理加密和证书管理。
genrsa           生成 RSA 私钥(PKCS#1 格式)。
-out server.key  指定输出文件 server.key(存储私钥)。
2048             指定密钥长度为 2048 位(常见长度包括 2048、3072、4096 位)。

建议2048以上,1024在nginx中重启时会提示错误:长度过小。

#  server.key 内容
-----BEGIN RSA PRIVATE KEY-----
···
···
···
-----END RSA PRIVATE KEY-----

私钥的编码格式通常分为 PKCS#1 和 PKCS#8。
PKCS#1 是 RSA 密钥结构标准,PKCS#1私钥通常使用 PEM 格式存储。
PEM(Privacy-Enhanced Mail)文件是 Base64 编码的文本格式。

PS:使用 genpkey 命令生成 PKCS#8 格式的 RSA 私钥
[root@docker-server cert]# openssl genpkey -algorithm RSA -out server.key -pkeyopt rsa_keygen_bits:2048
# server.key 内容
-----BEGIN PRIVATE KEY-----
···
···
···
-----END PRIVATE KEY-----

PKCS#8 和 PKCS#1 私钥格式可以互相转换。

# 2、生成csr(Certificate Signing Request证书签名请求)
[root@docker-server cert]# openssl req -new -key server.key -out server.csr
生成证书签名请求(CSR),CSR 是向 证书颁发机构(CA) 申请 SSL/TLS 证书时提交的文件。
openssl req      调用 OpenSSL 的 req(Request)模块,用于处理证书请求 csr。
-new             生成一个新的 CSR(不是已有证书的更新)。
-key server.key  使用 server.key 私钥生成 CSR,公钥通过私钥计算得出。
-out server.csr  生成的证书签名请求(CSR)保存到 server.csr 文件。

使用私钥计算出公钥,生成的CSR中会包含主体信息、公钥,用于将来签名。

填写证书信息,需输入:
国家(C):如 CN
省份(ST):如 Shandong
城市(L):如 Jinan
组织(O):如 YourCompanyName
部门(OU):如 IT
通用名称(CN):如 dev.domain.com
邮箱(emailAddress):如 dev@mail.com

将生成的server.csr提交给CA,CA通过它签发证书。自己作为ca角色的话,就自己签发。


# 3、颁发证书
[root@docker-server cert]# openssl x509 -req -in server.csr -signkey server.key -out server.crt -days 365
参数	            说明
-req	            表示使用的是 CSR 输入
-in server.csr	    输入的 CSR 文件
-signkey server.key	使用哪个私钥签发(此处的签名者和持有者相同)
-out server.crt	    输出生成的证书
-days 365	        有效期
这样生成的 server.crt 就是自签名证书,它的签名者就是它自己。
客户端(如浏览器)默认不信任它,除非你导入它为“受信任根证书”。

总结最后得到3个文件:
server.key 私钥
server.csr 证书签名请求 csr
server.crt 颁发的证书


# 其它
# 一条命令直接生成私钥和公钥
[root@docker-server a]# openssl req -x509 -newkey rsa:2048 -keyout key.pem -out cert.pem -days 365 -nodes -subj '/C=CN/ST=SHANDONG/L=JINAN/O=GAO DE TECH/OU=IT/CN=dev.xxx.com'
-nodes 是no des加密

# 提取查看公钥内容
[root@docker-server ca]# openssl x509 -in server.crt -noout -pubkey

# 查看证书信息
[root@docker-server ca]# openssl x509 -in server.crt -noout -text

2025-06-13
发表者 Venus
php使用自签名证书调用三方接口已关闭评论

php使用自签名证书调用三方接口

自己生成私钥和csr,将csr发给对方,对方为私有ca,给我们颁发证书(公钥),php代码需要配置证书、根证书及私钥访问对方接口。

对方给的证书只有服务器证书,没有给根证书,可以访问对方域名提取,或者命令行获取。

openssl s_client -connect x.x.xgaming.com:443 -showcerts


命令输出的比较多,通过判断 “CN =” 字段来确认是服务器证书、还是中间证书或者根证书。

用浏览器方式导出根证书最方便。

// 设置对方CA根证书(验证服务器身份)
curl_setopt($ch, CURLOPT_CAINFO, __DIR__ . "/ca.crt");
// 设置客户端证书和私钥(双向TLS用)
curl_setopt($ch, CURLOPT_SSLCERT, __DIR__ . "/prod-cert.pem");
curl_setopt($ch, CURLOPT_SSLKEY, __DIR__ . "/PrivateKey.key");

CURLOPT_SSLCERT → 向服务器提供客户端证书(公钥)。
CURLOPT_SSLKEY → 客户端私钥,用于 解密服务器返回的加密数据。
CURLOPT_CAINFO → 用于验证服务器的证书是否可信。

双向tls流程参考:
https://help.aliyun.com/zh/api-gateway/traditional-api-gateway/user-guide/mutual-tls-authentication
PS:通过 https://decoder.link/result 这个网站可以解析证书内容。

为什么要对方颁发证书给我们?因为对方是根ca,可以免去对方要求自己提供根ca证书的步骤。
# 可以通过下面命令测试mtls
openssl s_client -connect api.example.com:443 -cert client.crt -key client.key -CAfile ca.crt