项目场景:
开发一个web服务端,在本地电脑运行,网页可以通过http/https去访问:
问题描述:
如果网页通过https去访问,浏览器会提示非安全链接:
原因分析:
服务端没有证书,需要使用自签证书,然后在服务端中使用自签证书。
解决方案:
可以使用mkcert颁发证书,步骤如下:
1、点击下载mkcert.exe,或者GitHub下载,选择mkcert-v1.4.3-windows-amd64.exe:
2、生成根证书,cmd执行mkcert-v1.4.3-windows-amd64.exe -install
,在C:\Users\zdp\AppData\Local\mkcert中生成根证书,将该根证书安装在需要访问web服务端的电脑上。安装证书可以直接双击rootCA.crt:
也可以运行下面的命令:
可以看到本地电脑证书已经安装完成:
3、为服务端颁发证书,cmd执行mkcert-v1.4.3-windows-amd64.exe 127.0.0.1
,会生成证书,用于服务端:
服务端代码片段:
#include "openssl/ssl.h"
#include "openssl/err.h"
#define SERVER_ADDR "127.0.0.1" // 服务器地址
#define SERVER_PORT 53989
#define SSL_CERT_FILE "server-cert.pem"
#define SSL_KEY_FILE "server-key.pem"
SSL_CTX *m_sslCtx;
SOCKET m_sock_ssl;
SOCKET m_sock_ssl_ipv6;
int InitSSLServer() {
// SSL 库初始化
SSL_library_init();
// 载入所有 SSL 算法
OpenSSL_add_all_algorithms();
// 载入所有 SSL 错误消息
SSL_load_error_strings();
// 以 SSL V2 和 V3 标准兼容方式产生一个 SSL_CTX ,即 SSL Content Text
// 也可以用 SSLv2_server_method() 或 SSLv3_server_method() 单独表示 V2 或 V3标准
m_sslCtx = SSL_CTX_new(SSLv23_server_method());
if (m_sslCtx == NULL) {
OutputDebugStringA("Couldn't create the SSL method.");
return -1;
}
// 载入用户的数字证书, 此证书用来发送给客户端。证书里包含有公钥
if (SSL_CTX_use_certificate_file(m_sslCtx, SSL_CERT_FILE, SSL_FILETYPE_PEM) <= 0) {
OutputDebugStringA("Failure reading SSL certificate file.");
return -1;
}
// 载入用户私钥
if (SSL_CTX_use_PrivateKey_file(m_sslCtx, SSL_KEY_FILE, SSL_FILETYPE_PEM) <= 0) {
OutputDebugStringA("Failure reading private key file.");
return -1;
}
// 检查用户私钥是否正确
if (!SSL_CTX_check_private_key(m_sslCtx)) {
OutputDebugStringA("Private key does not match the certificate public key.");
return -1;
}
// 创建套接字
m_sock_ssl = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (m_sock_ssl == INVALID_SOCKET) {
OutputDebugStringA("Create m_sock_ssl failed.");
return -1;
}
// 绑定端口
int port = -1;
if ((port = BindPort(m_sock_ssl, SERVER_PORT + 1)) == -1) {
OutputDebugStringA("m_sock_ssl socket bind failed.");
return -1;
}
// 开始监听
if (listen(m_sock_ssl, 300) != 0) {
OutputDebugStringA("m_sock_ssl socket listen failed.");
return -1;
}
// 初始化IPV6 ssl socket
m_sock_ssl_ipv6 = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP);
if (m_sock_ssl_ipv6 != INVALID_SOCKET) {
if (BindPort(m_sock_ssl_ipv6, port, true) != -1) { // 和IPV4使用同一个端口
listen(m_sock_ssl_ipv6, 300);
}
} else {
OutputDebugStringA("IPV6 ssl socket Create failed.");
}
OutputDebugStringA("SSL security server initialization is complete!");
return 0;
}
之后再访问web服务端就是安全链接了(火狐浏览器不支持):