使用libevhtp搭建HTTPS SERVER(单向验证身份)
本文主要介绍使用libevhtp搭建一个HTTPS SERVER的方法,非加密的HTTP SERVER搭建方法,请点击此处 (本文的构建环境继承自该博客)。
本文将针对“单向验证身份”场景,介绍HTTPS SERVER的搭建方法。“双向验证身份”的场景,请点击此处。
1. 单向验证身份
一般的HTTPS服务都是只需要客户端验证服务器的身份就可以了。
例如我们想访问银行的网站,我们首先需要确认要访问的这个网站确实是真实的银行网站,而不是一个界面类似的、用来诱骗我们输入银行账号和密码的钓鱼网站,这就是我们作为客户端对银行进行身份验证的过程;而银行网站并不需要通过SSL/TLS来验证我们的身份,因为我们会通过在网页里输入银行账号和密码向服务器展示我们的身份。
我们可以通过以下步骤搭建单向验证身份的HTTPS SERVER。
1.1 生成服务器的证书文件
要搭建HTTPS服务器,需要使用HTTPS服务器的秘钥文件和证书文件。
生成HTTPS服务器的秘钥文件和证书文件的步骤如下:
1. 生成秘钥对(RSA)文件:
openssl genrsa -out server-key.pem 2048
2. 生成身份证申请(CSR)文件:
openssl req -new -key server-key.pem -out server-csr.pem -subj "/CN=192.168.213.133"
3. 签署身份证(CRT)文件:
openssl x509 -req -sha256 -days 365 -in server-csr.pem -signkey server-key.pem -out server-crt.pem
经过上面的3步,我们得到了HTTPS服务器的秘钥文件server-key.pem和证书文件server-crt.pem。
说明:
- 在上面的例子中,用来签署CSR文件的私钥和CSR里的公钥是一对儿,也就是说这是一个自签名(self-sign)的例子。通常情况下,我们会用一个CA的私钥来签署一个CSR,在双向验证身份的博文中会有相关介绍。
- 上述步骤中的参数需要根据实际情况进行调整,如HTTPS服务器的访问域名“/CN=192.168.213.133”。
1.2 调用libevhtp接口,构建HTTPS服务器
调用libevhtp接口,编写HTTPS服务器,代码(https_server.cpp)如下:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <getopt.h>#include "../log.h"
#include "internal.h"
#include "evhtp/evhtp.h"#ifndef EVHTP_DISABLE_SSL
// 回调方法的具体实现
static void http__callback_(evhtp_request_t* req, void* arg)
{evbuffer_add_reference(req->buffer_out, "foobar\n", 7, NULL, NULL);return evhtp_send_reply(req, EVHTP_RES_OK);
}// 认证客户端的相关信息
static int ssl__x509_verify_(int ok, X509_STORE_CTX* store)
{char buf[256];X509 * err_cert;int err;int depth;SSL * ssl;evhtp_connection_t * connection;evhtp_ssl_cfg_t * ssl_cfg;err_cert = X509_STORE_CTX_get_current_cert(store);err = X509_STORE_CTX_get_error(store);depth = X509_STORE_CTX_get_error_depth(store);ssl = (SSL*)X509_STORE_CTX_get_ex_data(store, SSL_get_ex_data_X509_STORE_CTX_idx());X509_NAME_oneline(X509_get_subject_name(err_cert), buf, 256);connection = (evhtp_connection_t*)SSL_get_app_data(ssl);ssl_cfg = connection->htp->ssl_cfg;if (depth > ssl_cfg->verify_depth){ok = 0;err = X509_V_ERR_CERT_CHAIN_TOO_LONG;X509_STORE_CTX_set_error(store, err);}if (!ok){log_error("SSL: verify error:num=%d:%s:depth=%d:%s", err, X509_verify_cert_error_string(err), depth, buf);}return ok;
}// https server参数枚举值
enum {OPTARG_CERT = 1000,OPTARG_KEY,OPTARG_CA,OPTARG_CAPATH,OPTARG_CIPHERS,OPTARG_VERIFY_PEER,OPTARG_ENFORCE_PEER_CERT,OPTARG_VERIFY_DEPTH,OPTARG_ENABLE_CACHE,OPTARG_CACHE_TIMEOUT,OPTARG_CACHE_SIZE,OPTARG_CTX_TIMEOUT,OPTARG_ENABLE_PROTOCOL,OPTARG_DISABLE_PROTOCOL
};// https server帮助信息
static const char* help ="Usage %s [opts] <host>:<port>\n"" -cert <file> : Server PEM-encoded X.509 Certificate file\n"" -key <file> : Server PEM-encoded Private Key file\n"" -ca <file> : File of PEM-encoded Server CA Certificates\n"" -capath <path> : Directory of PEM-encoded CA Certificates for Client Auth\n"" -ciphers <str> : Accepted SSL Ciphers\n"" -verify-peer : Enable SSL client verification\n"" -enforce-peer-cert : Reject clients without a cert\n"" -verify-depth <n> : Maximum depth of CA Certificates in Client Certificate verification\n"" -enable-protocol <p> : Enable one of the following protocols: SSLv2, SSLv3, TLSv1, or ALL\n"" -disable-protocol <p> : Disable one of the following protocols: SSLv2, SSLv3, TLSv1, or ALL\n"" -ctx-timeout <n> : SSL Session Timeout (SSL >= 1.0)\n";// 获取并解析用户输入的https server参数,配置evhtp的ssl信息
evhtp_ssl_cfg_t *parse__ssl_opts_(int argc, char** argv)
{int opt = 0;int long_index = 0;int ssl_verify_mode = 0;struct stat f_stat;evhtp_ssl_cfg_t* ssl_config = (evhtp_ssl_cfg_t*)calloc(1, sizeof(evhtp_ssl_cfg_t));ssl_config->ssl_opts = SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1;static struct option long_options[] = {{ "cert", required_argument, 0, OPTARG_CERT },{ "key", required_argument, 0, OPTARG_KEY },{ "ca", required_argument, 0, OPTARG_CA },{ "capath", required_argument, 0, OPTARG_CAPATH },{ "ciphers", required_argument, 0, OPTARG_CIPHERS },{ "verify-peer", no_argument, 0, OPTARG_VERIFY_PEER },{ "enforce-peer-cert", no_argument, 0, OPTARG_ENFORCE_PEER_CERT },{ "verify-depth", required_argument, 0, OPTARG_VERIFY_DEPTH },{ "enable-cache", no_argument, 0, OPTARG_ENABLE_CACHE },{ "cache-timeout", required_argument, 0, OPTARG_CACHE_TIMEOUT },{ "cache-size", required_argument, 0, OPTARG_CACHE_SIZE },{ "enable-protocol", required_argument, 0, OPTARG_ENABLE_PROTOCOL },{ "disable-protocol", required_argument, 0, OPTARG_DISABLE_PROTOCOL },{ "ctx-timeout", required_argument, 0, OPTARG_CTX_TIMEOUT },{ "help", no_argument, 0, 'h' },{ NULL, 0, 0, 0 }};// 获取用户输入的https server参数while ((opt = getopt_long_only(argc, argv, "", long_options, &long_index)) != -1) {switch (opt) {case 'h':printf(help, argv[0]);exit(EXIT_FAILURE);// 服务端证书文件case OPTARG_CERT:ssl_config->pemfile = strdup(optarg);break;// 服务端秘钥文件case OPTARG_KEY:ssl_config->privfile = strdup(optarg);break;// 签署服务器证书文件的CA证书文件case OPTARG_CA:ssl_config->cafile = strdup(optarg);break;case OPTARG_CAPATH:ssl_config->capath = strdup(optarg);break;case OPTARG_CIPHERS:ssl_config->ciphers = strdup(optarg);break;// 签署客户端证书文件的CA证书文件的最大深度case OPTARG_VERIFY_DEPTH:ssl_config->verify_depth = atoi(optarg);break;// 启用对于客户端的SSL认证case OPTARG_VERIFY_PEER:ssl_verify_mode |= SSL_VERIFY_PEER;break;// 拒绝没有证书文件的客户端的连接case OPTARG_ENFORCE_PEER_CERT:ssl_verify_mode |= SSL_VERIFY_FAIL_IF_NO_PEER_CERT;break;case OPTARG_ENABLE_CACHE:ssl_config->scache_type = evhtp_ssl_scache_type_internal;break;case OPTARG_CACHE_TIMEOUT:ssl_config->scache_timeout = atoi(optarg);break;case OPTARG_CACHE_SIZE:ssl_config->scache_size = atoi(optarg);break;case OPTARG_CTX_TIMEOUT:ssl_config->ssl_ctx_timeout = atoi(optarg);break;case OPTARG_ENABLE_PROTOCOL:if (!strcasecmp(optarg, "SSLv2")){ssl_config->ssl_opts &= ~SSL_OP_NO_SSLv2;}else if (!strcasecmp(optarg, "SSLv3")){ssl_config->ssl_opts &= ~SSL_OP_NO_SSLv3;}else if (!strcasecmp(optarg, "TLSv1")){ssl_config->ssl_opts &= ~SSL_OP_NO_TLSv1;}else if (!strcasecmp(optarg, "ALL")){ssl_config->ssl_opts = 0;}break;case OPTARG_DISABLE_PROTOCOL:if (!strcasecmp(optarg, "SSLv2")){ssl_config->ssl_opts |= SSL_OP_NO_SSLv2;}else if (!strcasecmp(optarg, "SSLv3")){ssl_config->ssl_opts |= SSL_OP_NO_SSLv3;}else if (!strcasecmp(optarg, "TLSv1")){ssl_config->ssl_opts |= SSL_OP_NO_TLSv1;}else if (!strcasecmp(optarg, "ALL")){ssl_config->ssl_opts = SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1;}break;default:break;} /* switch */}// 需要对客户端进行认证的情况if (ssl_verify_mode != 0){ssl_config->verify_peer = ssl_verify_mode;ssl_config->x509_verify_cb = ssl__x509_verify_;}// 检查服务端证书文件if (ssl_config->pemfile){if (stat(ssl_config->pemfile, &f_stat) != 0){log_error("Cannot load SSL cert '%s' (%s)", ssl_config->pemfile, strerror(errno));exit(EXIT_FAILURE);}}// 检查服务端秘钥文件if (ssl_config->privfile){if (stat(ssl_config->privfile, &f_stat) != 0){log_error("Cannot load SSL key '%s' (%s)", ssl_config->privfile, strerror(errno));exit(EXIT_FAILURE);}}// 检查签署服务器证书文件的CA证书文件if (ssl_config->cafile){if (stat(ssl_config->cafile, &f_stat) != 0){log_error("Cannot find SSL CA File '%s' (%s)", ssl_config->cafile, strerror(errno));exit(EXIT_FAILURE);}}if (ssl_config->capath) {if (stat(ssl_config->capath, &f_stat) != 0) {log_error("Cannot find SSL CA PATH '%s' (%s)", ssl_config->capath, strerror(errno));exit(EXIT_FAILURE);}}return ssl_config;
}
#endifint main(int argc, char **argv)
{
#ifndef EVHTP_DISABLE_SSLstruct event_base *evbase = event_base_new();evhtp_alloc_assert(evbase);evhtp_t *htp = evhtp_new(evbase, NULL);evhtp_alloc_assert(htp);// 根据用户输入的https server参数,初始化evhtp的ssl相关配置evhtp_ssl_init(htp, parse__ssl_opts_(argc, argv));// 设置回调函数evhtp_set_gencb(htp, http__callback_, NULL);// 监听本机IP"192.168.213.133"的4443端口, backlog为128evhtp_bind_socket(htp, "192.168.213.133", 4443, 128);log_info("[https server info] https://192.168.213.133:4443/");/* 进入循环、监听连接,http server开始工作 */event_base_loop(evbase, 0);return 0;
#elselog_error("Not compiled with SSL support, go away");return EXIT_FAILURE;
#endif
}
编译生成HTTPS服务器程序,命令如下:
g++ -o https_server https_server.cpp -I/opt/liitdar/libevhtp/libevhtp-1.2.15/include/ -L/opt/liitdar/libevhtp/libevhtp-1.2.15/build/ -levhtp -levent -lpthread -levent_openssl -lssl -lcrypto
说明:
- 需要根据实际情况设置头文件路径,并在头文件路径中添加需要的头文件;
- 需要根据实际情况设置静态库 libevhtp.a 的地址;
- 因为libevhtp的静态库 libevhtp.a 中包含了一些ssl的内容,所以在我们使用该静态库时,也需要连接一下ssl的相关库。
1.3 测试HTTPS服务器
打开一个终端,运行刚刚生成的HTTPS服务器程序,如下:
./https_server -cert ssl/server-crt.pem -key ssl/server-key.pem
在客户端机器上,打开一个终端,使用curl命令测试HTTPS服务器,如下:
curl https://192.168.213.133:4443/ --cacert ssl/server-crt.pem
说明:上述命令使用的HTTPS服务器的证书和秘钥是在本文前面生成的。
上面的curl命令的执行结果如下:
如果客户端的终端中出现上述信息,说明单向身份验证的HTTPS服务器部署成功了。
使用libevhtp搭建HTTPS SERVER(单向验证身份)相关推荐
- android搭建https,android 搭建https Server(示例代码)
在android上采用http协议的服务器,需求有点奇葩,非要用https更是醉了.这里只要求单向https认证,不要双向认证. 本文采用的开源框架Nanohttpd( https://github. ...
- 使用nodejs搭建HTTPS server
From 我的简书 第一步:创建一个项目目录,npm init初始化项目后,安装express. npm install express --save 第二步:新建http.js文件,初始代码如下. ...
- HTTPS实战之单向验证和双向验证
转载自:https://mp.weixin.qq.com/s/UiGEzXoCn3F66NRz_T9crA 原创: 涛哥 coding涛 6月9日 作者对https 解释的入目三分啊 (全文太长,太懒 ...
- HTTPS的SSL单向验证和双向验证
HTTPS的SSL单向验证和双向验证 HTTPs利用SSL/TLS建立安全信道,加密数据包,主要目的是提供对网站服务器的身份认证,同时保护交换数据的安全性与完整性 SSL/TLS TLS在传输 ...
- 怎样更改SQL Server 2008的身份验证方式
大家都知道sql server 有两种登录验证方式,即sql server验证方式和windows验证方式,但是sql server默认的是windows登录验证方式,我们如何启用sql server ...
- 如何更改SQL Server 2005的身份验证模式
安装MS SQL Server 2005时,缺省为Windows身份验证模式,刚开始不知道怎么修改为SQL Server和Windows混合身份验证模式,只好重装,然后选择为混合模式,后来发现,原来装 ...
- iRedmail搭建 集成AD以进行身份验证和地址簿
iRedmail搭建 & 集成AD以进行身份验证和地址簿 注1:官网搭建文档和集成AD文档写的很详细,在此不做详细步骤 搭建链接:https://docs.iredmail.org/insta ...
- iOS封装HTTPS双向和单向验证
1.HttpsUtil (1) 对双向和单向验证的封装 #import <Foundation/Foundation.h> #import "AFNetworking.h&quo ...
- SQL Server 数据库之身份验证和访问控制
身份验证和访问控制 1. 身份验证模式 1.1 Window 身份验证模式 1.2 混合身份验证模式 2. 管理登录名 2.1 创建 Windows 登录名 2.2 创建 SQL Server 登录名 ...
- 微软SQL服务器登录,Microsoft SQL Server 【Windows 身份验证】和 【sa】都无法登录的解决方案...
1.修改启动参数:打开[SQL Server 配置管理器(SQL Server Configuration Manager)]→右键[SQL Server(MSSQLSERVER)]属性→高级(Adv ...
最新文章
- python使用np.argsort对一维numpy概率值数据排序获取升序索引、获取的top索引(例如top2、top5、top10)索引二维numpy数组中对应的原始数据:原始数据概率最小的头部数据
- java 99乘法表对齐_Java实现九九乘法表的完整实例(对齐版)
- 【PP操作手册】工程变更创建的创建
- php分页类代码,php 分页类 扩展代码
- js常用reduce方法
- 解决Windows下运行出现ModuleNotFoundError: No module named xxx问题
- DPDK跟踪库:trace library
- python2.7.12源码编译
- ubuntu16.04 安装Opencv 3.1.0 import cv2 报错ImportError: No module named hdf5
- NXP S32K146 CAN通讯 TJA1043(二)
- SPSS(基础篇09)--拆分数据文件
- HTML5:爱奇艺首页图片轮播效果
- 【报错】arXiv上传文章出现XXX.sty not found
- 工科硕士毕业14年,谈谈我的经验教训
- mysql uid怎么获取_新浪微博API如何获取uid,并根据uid获取用户的基本信息
- python等比例压缩图片_python图片等比例压缩
- 新型压网技术—金刚网
- UReport2 - 套打实现
- ps中图层放到顶层的快捷键是什么?
- 改变字符串中指定字符的颜色