参考https://blog.csdn.net/qq_38502914/article/details/124630727
相关服务:美国站群服务器
1.安装OpenSSL
下载地址: Win32/Win64 OpenSSL Installer for Windows - Shining Light Productions
安装到第二个选项时,选择安装到指定的/bin目录下。

下载好后将两个dll拷贝到:

然后在qt pro里导入:
LIBS += -LD:\OpenSSL-Win64\lib -llibcrypto -llibssl
INCLUDEPATH += D:\OpenSSL-Win64\include
如果在公司项目中,则需要自己将dll和libs还有include拷贝到工程里,指定生成exe路径
2.SSL证书介绍
常见的SSL证书文件后缀扩展名说明:
①*.DER或*.CER文件: 带有这类后缀扩展名的SSL证书文件是二进制格式,只含有SSL证书信息,不包含私钥。
②*.CRT文件: 这样的证书文件可以是二进制格式,也可以是文本格式,一般均为文本格式,功能与 *.DER及*.CER证书文件相同。
③*.PEM文件: 这样的证书文件一般是文本格式,可以存放证书或私钥,或者两者都包含。 *.PEM 文件如果只包含私钥,一般用*.KEY文件代替。
④*.PFX或*.P12文件: 这样的证书文件是二进制格式,同时包含证书和私钥,且一般有密码保护。
之所以使用证书,是确保服务器地址有效性,主要是通过CA证书与服务器证书进行对比,也可以实现数据传输的加密处理,避免被劫持和篡改
3.创建SSL证书
*.csr文件:证书签名请求文件
*.key文件:私钥文件
*.crt文件:证书文件
生成私钥和证书
// CN非常很重要,必须和请求url的地址保持一致
openssl req -newkey rsa:2048 -nodes -keyout server.key -x509 -days 3650 -out server.crt -subj "/C=CN/ST=Shanghai/L=Shanghai/O=xxx/OU=xxx/CN=10.0.1.160/[email protected]"
req: 配置参数-x509指定使用 X.509证书签名请求管理(certificate signing request (CSR))."X.509" 是一个公钥代表that SSL and TLS adheres to for its key and certificate management.
-nodes: 告诉OpenSSL生产证书时忽略密码环节.(因为我们需要Nginx自动读取这个文件,而不是以用户交互的形式)。
-days 36500: 证书有效期,100年
-newkey rsa: 2048: 同时产生一个新证书和一个新的SSL key(加密强度为RSA 2048)
-keyout: SSL输出文件名
-out: 证书生成文件名
C : 地区,如中国为 CN,美国为 US
CT: 省份
L: 所在地的市/县/区
O: 填单位/机构/企业合法的名称,比如baidu
OU: 填部门名称
CN: 填域名,由于我们是ip访问,所以填ip,否则填域名,我们在验证服务器证书时,会验证Common Name与http请求的url域名是否匹配,如果不匹配,ssl会返回错误。
emailAddress: 邮件地址
生成了server.crt server.key
nginx开启ssl模块
由于我这里开启的,所以跳过
生成客户端证书
执行命令:
openssl genrsa -out client.key 2048
openssl req -new -key client.key -out client.csr
Country Name (2 letter code) [AU]:CN // 如中国为 CN,美国为 US
State or Province Name (full name) [Some-State]:Shanghai
Locality Name (eg, city) []:Shanghai // 填您所在地的市/县/区
Organization Name (eg, company) [Internet Widgits Pty Ltd]:puniu // 填单位/机构/企业合法的名称
Organizational Unit Name (eg, section) []:xxxClient // 填部门名称
Common Name (e.g. server FQDN or YOUR name) []:xxxClient // 填域名,客户端随便填
Email Address []: [email protected] // 邮件地址,可以不必输入,按回车跳过
A challenge password []: # 私钥保护密码,可直接回车
An optional company name []: # 一个可选公司名称,可直接回车
openssl x509 -req -days 3650 -in client.csr -signkey client.key -out client.crt
然后得到: client.key client.csr client.crt
配置nginx
服务器只需要服务器证书和私钥以及客户端证书即可
打开配置文件 nano /etc/nginx/nginx.conf:
修改如下所示:
server {
listen 8081;
listen 443 ssl; # 监听443端口, 开启ssl(必须)
listen [::]:8081;
server_name 10.0.1.160; # 必须和服务器证书CN值保持一致,否则会返回ssl错误
root /usr/share/nginx/html;
ssl on;
# 引用ssl证书(必须,如果放在nginx/conf/ssl下可以用相对路径,其他位置必须用绝对路径)
ssl_certificate /etc/pki/CA/lisense/server.crt;
ssl_certificate_key /etc/pki/CA/lisense/server.key;
ssl_client_certificate /etc/pki/CA/lisense/client.crt;
ssl_verify_client on; # 开启客户端传输
# 协议优化(可选,优化https协议,增强安全性)
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
//...其它配置
}
更新服务器配置
nginx -t // 查看配置,返回ok,则可以更新配置
nginx -s reload // 更新配置
注:记得开启防火墙的443端口 firewall-cmd --zone=public --add_port=443/tcp permanent
4.QT客户端使用https访问服务器验证
qDebug() << "支持OpenSSL: " << QSslSocket::supportsSsl();
// 客户端证书
QFile crtFile("D:/OpenSSL-Win64/bin/client.crt");
crtFile.open(QIODevice::ReadOnly);
const QSslCertificate certificate(&crtFile, QSsl::Pem);
crtFile.close();
// 客户端私钥
QFile keyFile("D:/OpenSSL-Win64/bin/client.key");
keyFile.open(QIODevice::ReadOnly);
const QSslKey prvateKey(&keyFile, QSsl::Rsa);
keyFile.close();
// 通过QSslConfiguration 类进行SSL连接配置
QSslConfiguration config ;
//设置SSL验证模式 客户端与服务器进行双向校验
config.setPeerVerifyMode(QSslSocket::VerifyPeer);
//使用TLS 1.2 协议版本 和服务器保持一致
config.setProtocol(QSsl::TlsV1_2);
config.setPrivateKey(prvateKey);
config.setLocalCertificate(certificate);
//由于是自签名的服务器端证书,我们还得将服务器端的证书叫入到CA证书数据库中,否则服务器端证书将验证失败。
QList<QSslCertificate> caCerList;
QFile fileServCrt("D:/OpenSSL-Win64/bin/server.crt");
fileServCrt.open(QIODevice::ReadOnly);
const QSslCertificate cACertificate(&fileServCrt, QSsl::Pem);
//将服务证书加入到CA列表中
caCerList << cACertificate;
config.setCaCertificates(caCerList);
//网络连接管路
QNetworkAccessManager *manager = new QNetworkAccessManager(this);
QUrl url(QUrl("https://10.0.1.160:443/static/SSD/20220621/123.txt"));
QNetworkRequest request(url);
//加入ssl配置信息
request.setSslConfiguration(config);
//设置rest api 数据内容为json格式
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
connect(manager, &QNetworkAccessManager::finished, this, [](QNetworkReply* reply){
QByteArray byteArray = reply->readAll();
qDebug()<<"finished:"<<reply->error()<<byteArray.length()<<byteArray;
QSslCertificate cert = reply->sslConfiguration().peerCertificate();
qDebug()<<"打印服务器证书:";
qDebug()<<cert.isNull();
qDebug()<<cert.issuerDisplayName();
qDebug()<<cert.subjectDisplayName();
qDebug()<<cert.version();
qDebug()<<"serialNumber"<<cert.serialNumber();
qDebug()<<cert.issuerInfo(QSslCertificate::Organization);
qDebug()<<"CommonName: "<<cert.issuerInfo(QSslCertificate::CommonName);
qDebug()<<cert.issuerInfo(QSslCertificate::LocalityName);
qDebug()<<cert.issuerInfo(QSslCertificate::OrganizationalUnitName);
qDebug()<<cert.issuerInfo(QSslCertificate::CountryName);
qDebug()<<cert.issuerInfo(QSslCertificate::StateOrProvinceName);
qDebug()<<cert.issuerInfo(QSslCertificate::DistinguishedNameQualifier);
qDebug()<<cert.issuerInfo(QSslCertificate::SerialNumber);
qDebug()<<cert.issuerInfo(QSslCertificate::EmailAddress);
qDebug()<<cert.effectiveDate();
qDebug()<<cert.expiryDate();
});
connect(manager, &QNetworkAccessManager::sslErrors, this, [](QNetworkReply*reply,const QList<QSslError>& errors){
qDebug()<<"sslErrors:"<<errors;
});
manager->get(request);
总结
如果CA证书和服务器证书不匹配,则报错:
sslErrors: ("The certificate is self-signed, and untrusted")
如果客户端证书与服务器绑定的客户端证书不匹配,则报错:
QNetworkReply::UnknownNetworkError
如果忽略SSL错误,可以连接QNetworkAccessManager::sslErrors信号槽,然后在槽函数ignoreSslErrors即可.
如果是web浏览器,则重写QWebEnginePage类,重写下面函数即可:
[virtual protected] bool QWebEnginePage::certificateError(const QWebEngineCertificateError &certificateError)
本文地址:https://www.idc504.com/news/9_12885.html





