ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

libwebsockets 内存证书 TLS 最小 HTTP 服务器实战:minimal-http-server-tls-mem 原理与配置详解

libwebsockets 内存证书 TLS 最小 HTTP 服务器实战:minimal-http-server-tls-mem 原理与配置详解 人工智能AI Agent多模态语音AI 应用【免费下载链接】ten-frameworkOpen-source framework for conversational voice AI agents项目地址https://gitcode.com/TEN-framework/ten-framework点击查看免费下载导读minimal-http-server-tls-mem是 libwebsocketslwsminimal-examples 中专门演示「从内存缓冲区而非磁盘文件加载 TLS 证书与私钥」的示例同一进程内用 PEM 与 DER 两种内存证书分别初始化两个 HTTPS vhost分别监听 7681、7682 端口。阅读本文后你将掌握 lws 内存证书相关的info字段配置、底层 PEM/DER 自动识别与转换机制、自签名证书生成与 DER 数组转换方法以及如何让该服务器开箱支持 HTTP/2。一、示例定位与文件证书版 minimal-http-server-tls 的差异在 third_party/libwebsockets/minimal-examples/http-server 目录下lws 提供了一组最小 HTTPS 服务器示例minimal-http-server-tls通过ssl_cert_filepath/ssl_private_key_filepath指向磁盘上的localhost-100y.cert与localhost-100y.key文件见 minimal-http-server-tls.cminimal-http-server-tls-mem与前者功能一致但证书与私钥完全以内嵌内存缓冲区的形式提供不访问文件系统。内存证书方式的核心价值在于证书可以编译进二进制const段避免部署时携带敏感证书文件适合嵌入式、单文件分发或需要把证书打包进固件/镜像的场景同时展示了 lws 对PEM 与 DER 两种编码的统一支持——两个 vhost 分别使用 PEM 与 DER验证同一套初始化代码可以处理两种格式。从示例的结构可以推断该示例用两个 vhost 承载两种证书格式first7681PEM与second7682DER共享同一个挂载点与 404 页面配置。二、构建与运行示例根目录内即包含完整的 CMakeLists.txt构建方式与官方 README 一致$ cmake . makeCMake 配置阶段会通过require_lws_config()检查 lws 的编译选项只有同时满足以下三项时才会生成可执行文件CMakeLists.txtLWS_ROLE_H1HTTP/1 角色LWS_WITH_SERVER服务端支持LWS_WITH_TLSTLS 支持运行方式与启动日志如下日志中的时间戳为示例作者当时的环境实际运行会不同$ ./lws-minimal-http-server-tls-mem [2019/02/14 14:46:40:9783] USER: LWS minimal http server TLS | visit https://localhost:7681 [2019/02/14 14:46:40:9784] NOTICE: Using SSL mode [2019/02/14 14:46:40:9784] NOTICE: lws_tls_server_vhost_backend_init: vh first: mem CA OK parsing as der [2019/02/14 14:46:40:9849] NOTICE: no client cert required [2019/02/14 14:46:40:9849] NOTICE: created client ssl context for first [2019/02/14 14:46:40:9849] NOTICE: Using SSL mode [2019/02/14 14:46:40:9850] NOTICE: lws_tls_server_vhost_backend_init: vh second: mem CA OK parsing as der [2019/02/14 14:46:40:9894] NOTICE: no client cert required [2019/02/14 14:46:40:9894] NOTICE: created client ssl context for second [2019/02/14 14:46:40:9894] NOTICE: vhost first: cert expiry: 36167d [2019/02/14 14:46:40:9894] NOTICE: vhost second: cert expiry: 36167d [2018/03/20 13:23:14:0207] NOTICE: vhost default: cert expiry: 730459d日志中值得注意的几处Using SSL mode两个 vhost 均以 SSL 模式启动vh first: mem CA OK/vh second: mem CA OK内存 CA 校验通过这与 mbedtls-server.c 中的lwsl_notice(%s: vh %s: mem CA OK\n, ...)输出对应parsing as derDER 路径上的解析提示cert expiry: 36167d当前证书剩余有效期约 36167 天约 99 年对应自签名证书从 2018-03-20 起 100 年有效期的设计。启动后浏览器访问两个地址即可验证https://127.0.0.1:7681PEM 内存证书 vhosthttps://127.0.0.1:7682DER 内存证书 vhost由于使用的是自签名证书浏览器会提示证书不受信任需要手动添加例外后继续访问详见下文「自签名证书生成」一节。三、核心原理从文件证书到内存证书3.1 info 结构体中的内存证书字段lws 的 vhost 初始化信息统一存放在struct lws_context_creation_info中其字段定义于 lws-context-vhost.h。与内存证书相关的核心字段如下字段类型说明server_ssl_cert_memconst void *服务端证书的内存缓冲区PEM 或 DER 均可ssl_cert_filepath的替代方案二者至多一个非 NULL见头文件 L435-L438server_ssl_cert_mem_lenunsigned int上述证书缓冲区的字节长度server_ssl_private_key_memconst void *服务端私钥的内存缓冲区ssl_private_key_filepath的替代方案二者至多一个非 NULLserver_ssl_private_key_mem_lenunsigned int上述私钥缓冲区的字节长度server_ssl_ca_memconst void *CA 证书的内存缓冲区ssl_ca_filepath的替代方案server_ssl_ca_mem_lenunsigned intCA 缓冲区的字节长度头文件对ssl_cert_filepath的注释明确指出也可以直接用内存缓冲区设置单个 DER 或 PEM 证书lws-context-vhost.h私钥字段同理lws-context-vhost.h。3.2 示例中的两个 vhost 配置在 minimal-http-server-tls-mem.c 中先创建 context再显式创建两个 vhost/* 第一个 vhostPEM 内存证书端口 7681 */ info.port 7681; info.mounts mount; info.error_document_404 /404.html; info.server_ssl_cert_mem cert_pem; info.server_ssl_cert_mem_len (unsigned int)strlen(cert_pem); info.server_ssl_private_key_mem key_pem; info.server_ssl_private_key_mem_len (unsigned int)strlen(key_pem); info.vhost_name first; if (!lws_create_vhost(context, info)) { ... } /* 第二个 vhostDER 内存证书端口 7682 */ info.port 7682; info.server_ssl_cert_mem cert_der; info.server_ssl_cert_mem_len (unsigned int)sizeof(cert_der); info.server_ssl_private_key_mem key_der; info.server_ssl_private_key_mem_len (unsigned int)sizeof(key_der); info.vhost_name second;注意两个细节长度计算方式不同PEM 是以\n结尾的字符串用strlen()即可DER 是二进制数组必须用sizeof()。传错长度会导致解析失败。LWS_SERVER_OPTION_EXPLICIT_VHOSTS必须开启因为示例没有在lws_create_context()阶段指定端口而是之后用lws_create_vhost()显式逐个创建context 级info.options必须包含该标志见 minimal-http-server-tls-mem.c。此外示例的 context 级 options 还包含LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT做全局 SSL 初始化LWS_SERVER_OPTION_HTTP_HEADERS_SECURITY_BEST_PRACTICES_ENFORCE强制启用 HTTP 安全头最佳实践命令行加-h时追加LWS_SERVER_OPTION_VHOST_UPG_STRICT_HOST_CHECK严格 Host 校验用于防止 DNS 重绑定类攻击命令行-d可设置日志级别lws_cmdline_option(argc, argv, -d)解析后调用lws_set_log_level。3.3 静态挂载点 mount示例通过struct lws_http_mount mount把静态目录挂到根路径minimal-http-server-tls-mem.c.mountpoint /URL 挂载点.origin ./mount-origin服务文件所在目录相对启动目录.def index.html默认首页文件名.origin_protocol LWSMPRO_FILE以普通文件方式提供内容。./mount-origin目录内包含 index.html、404.html、example.js 等静态资源error_document_404 /404.html指定了 404 错误页。四、源码级深入内存证书在 lws 内部的加载链路4.1 从 vhost 初始化到证书装载两个 TLS 后端OpenSSL 与 mbedtls都实现了同名函数lws_tls_server_vhost_backend_init()OpenSSL 实现位于 openssl-server.cmbedtls 实现位于 mbedtls-server.c。在 OpenSSL 路径中函数依次完成创建SSL_CTXSSL_CTX_new(SSLv23_server_method())通过SSL_CTX_set_options禁用 SSLv2/SSLv3 等不安全选项openssl-server.c设置 SNIServer Name Indication回调使每个 vhost 的证书按域名正确选择判断是否进入证书装载if (!vhost-tls.use_ssl || (!info-ssl_cert_filepath !info-server_ssl_cert_mem)) return 0;openssl-server.c——文件路径与内存缓冲二者都为空时直接跳过调用lws_tls_server_certs_load()统一装载证书与私钥openssl-server.c。lws_tls_server_certs_load()定义于 openssl-server.c会先做通用证书检查lws_tls_generic_cert_checks然后若同时给了证书文件路径走SSL_CTX_use_certificate_chain_file/SSL_CTX_use_PrivateKey_file的文件加载路径否则走 DER or PEM, file or memory image 的统一路径源码注释原文见 openssl-server.c把内存/文件内容统一转换为 DER 字节流后分别调用SSL_CTX_use_certificate_ASN1与SSL_CTX_use_PrivateKey_ASN1装载私钥部分先按 RSA 尝试失败再按 EC 尝试openssl-server.c。4.2 PEM/DER 自动识别关键函数 lws_tls_alloc_pem_to_der_file无论后端是 OpenSSL 还是 mbedtlsPEM→DER 的统一转换都收敛到lws_tls_alloc_pem_to_der_file()定义于 tls.c。其识别逻辑非常直观if (strncmp((char *)p, -----, 5)) { /* take it as being already DER */ ... } /* PEM - DER */若输入缓冲区不以-----开头PEM 的 base64 头标记直接按「已经是 DER」处理原样拷贝若以-----开头则按 PEM 处理跳过首行-----BEGIN ...-----、剔除末行-----END ...-----对中间 base64 部分做解码得到 DER。该函数同时服务于文件与内存两种来源filename为空时使用inbuf/inlen。源码注释特别强调内存输入的缓冲区可能位于只读的 const 段因此解码输出必须单独分配tls.c这也解释了示例中证书为何被声明为static const数组。mbedtls 后端走相同的函数与SSL_CTX_use_certificate_ASN1/SSL_CTX_use_PrivateKey_ASN1组合见 mbedtls-server.c并输出mem CA OK、no client cert required等日志。由此可见「内存证书」并非 lws 的旁路特性而是与文件证书共用同一条统一的装载链路只是数据来源从文件切换为内存缓冲区。五、自签名证书的生成与替换5.1 生成命令示例自带的自签名证书覆盖localhost自 2018-03-20 起有效期 100 年由以下命令生成echo -e GB\nErewhon\nAll around\nlibwebsockets-test\n\nlocalhost\nnoneinvalid.org\n | openssl req -new -newkey rsa:4096 -days 36500 -nodes -x509 -keyout localhost-100y.key -out localhost-100y.cert其中各行为openssl req交互提示的依次应答含义为GB国家代码Country NameErewhon省份/州StateAll around城市Localitylibwebsockets-test组织名Organization空行组织单位Organizational Unit留空localhost通用名 CN必须与访问主机名匹配noneinvalid.org邮箱。命令参数说明-newkey rsa:4096生成 4096 位 RSA 新密钥-days 36500证书有效期 36500 天约 100 年-nodes私钥不加密无 passphrase便于服务器自动加载-x509直接输出自签名 X.509 证书-keyout/-out私钥与证书输出文件。5.2 替换为商用证书README 明确说明可以将这两个文件替换为匹配你主机名的商用证书。使用时把新的证书与私钥内容PEM 文本或 DER 字节替换进cert_pem/key_pem/cert_der/key_der内存数组即可无需改动其余代码。需要留意证书 CN 必须与浏览器访问的域名一致否则仍会提示证书错误商用证书通常有效期远短于 100 年需自行评估证书更新策略若证书包含证书链中间 CA需把完整链按顺序拼接进同一缓冲区。5.3 从 PEM 生成 DER 十六进制数组示例的 DER 数组正是由 PEM 文件通过一条管道命令转换而来README 原文$ cat ../minimal-http-server-tls/localhost-100y.key | grep -v ^- | base64 -d | hexdump -C | tr -s | cut -d -f2- | cut -d -f-16 | sed s/|.*//g | sed s/0000.*//g | sed s/^/0x/g | sed s/\ /\,\ 0x/g | sed s/\$/,/g | sed s/0x,//g各段的作用拆解如下管道段作用cat localhost-100y.key读取 PEM 私钥文本grep -v ^-剔除-----BEGIN/END-----行只留 base64 正文base64 -dbase64 解码为二进制 DERhexdump -C以十六进制ASCII 两列输出tr -s /cut -d -f2-/cut -d -f-16提取每行 16 个十六进制字节去掉 ASCII 列sed s/|.*//g/sed s/0000.*//g清理地址偏移与全零行残留后续sed序列逐字节加0x前缀、逗号分隔、行尾加逗号拼成 C 数组转换产物即 minimal-http-server-tls-mem.c 中的cert_der[]与key_der[]数组。同理也可对localhost-100y.cert执行相同操作生成证书 DER 数组。六、HTTP/2 支持开箱即用README 指出如果 lws 在 cmake 阶段以-DLWS_WITH_HTTP21构建该服务器即可开箱支持 HTTP/2。也就是说只要 TLS 就绪且构建开启 HTTP/2 编译选项服务端会自动通过 ALPN 协商升级到 h2示例代码无需任何改动。页面侧example.js 会检测当前传输协议if (transport_protocol h2) document.getElementById(transport).innerHTML img src\/http2.png\;即若页面是通过 HTTP/2 加载的performance.timing.nextHopProtocol h2页面上会显示 http2.png 标志否则留空。这也是快速验证 HTTP/2 是否生效的直观手段。七、验证与调试要点浏览器访问分别访问https://127.0.0.1:7681与https://127.0.0.1:7682。两个端口的内容来自同一./mount-origin目录唯一区别是证书编码来源PEM vs DER可用于验证两种编码在内存装载下的行为一致性。自签名例外因为证书是自签名的浏览器会拦截需在高级选项中选择「继续访问/添加例外」。日志级别运行时可加-d指定日志级别数字如-d 255输出全部调试日志帮助排查证书解析问题注意 lws 需以 DEBUG 构建-DCMAKE_BUILD_TYPEDEBUG才能输出 NOTICE 以上更细的日志见 minimal-http-server-tls-mem.c 注释。404 页面验证访问https://127.0.0.1:7681/notextant.html等不存在路径会命中error_document_404 /404.htmlindex.html 也内置了指向不存在页面的测试链接。八、与文件证书版的对比与适用场景对照同目录下的 minimal-http-server-tls.c两者唯一的实质差异就是证书来源文件版info.ssl_cert_filepath localhost-100y.cert; info.ssl_private_key_filepath localhost-100y.key;内存版info.server_ssl_cert_mem / info.server_ssl_private_key_mem指向内嵌数组。底层装载路径完全一致。由此可以总结内存证书的适用场景单二进制分发证书随程序编译进二进制无需在部署目录放置敏感证书文件嵌入式/固件场景证书作为只读数据段的一部分打包进镜像证书内容受控场景证书来源由编译期决定避免运行时被替换为无效文件对照验证可用该示例快速验证同一套代码对 PEM/DER 两种编码的兼容性作为自研 TLS 集成的最小复现模板。如需在 lws 之上构建更完整的功能WebSocket 传输、多 vhost 隔离、客户端证书等minimal-examples 目录下还有大量可直接参考的同族示例如minimal-http-server-multivhost、minimal-http-server-tls-80等其构建方式与本示例一致可作为进一步扩展的起点。赞分享人工智能AI Agent多模态语音AI 应用【免费下载链接】ten-frameworkOpen-source framework for conversational voice AI agents项目地址https://gitcode.com/TEN-framework/ten-framework点击查看免费下载相关推荐基于 libwebsockets 的最小化 HTTPS 服务器minimal-http-server-tls 实战与源码解析基于 libwebsockets 的最小化 HTTPS 服务器minimal http server tls 实战与源码解析 本指南以 TEN framewo人工智能AI Agent多模态语音AI 应用libwebsockets minimal-http-server-tls-80 示例深度解析80 端口 HTTP 自动跳转 HTTPS 的最小 TLS 服务器实现libwebsockets minimal http server tls 80 示例深度解析80 端口 HTTP 自动跳转 HTTPS 的最小 TLS 服务人工智能AI Agent多模态语音AI 应用libwebsockets 最小化 HTTP 服务器示例详解eventlib SMP 多线程事件循环minimal-http-server-eventlib-smplibwebsockets 最小化 HTTP 服务器示例详解eventlib SMP 多线程事件循环minimal http server eventl人工智能AI Agent多模态语音AI 应用上一篇Envoy 网络过滤器通用模糊测试框架ReadFilter / WriteFilter Fuzzer 接入与实践指南下一篇绝区零自动化助手终极指南告别重复点击的智能解决方案创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表