xfy 941c44b798 docs: 添加 Lua 嵌入分析文档
- 新增 lua-embed-analysis.md 技术分析文档
- 新增 lua-nginx-module 文档目录
- 更新 gitignore 允许跟踪 docs/lua-nginx-module/

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-10 11:20:57 +08:00

5.6 KiB

lua-nginx-module SSL/TLS 功能

本文档详细说明 lua-nginx-module 的 SSL/TLS 相关功能。


一、核心文件

文件 说明
src/ngx_http_lua_ssl_certby.c 动态证书选择
src/ngx_http_lua_ssl_session_storeby.c Session 存储回调
src/ngx_http_lua_ssl_session_fetchby.c Session 获取回调
src/ngx_http_lua_ssl_client_helloby.c Client Hello 处理
src/ngx_http_lua_ssl.c SSL 上下文初始化

二、ssl_certificate_by_lua - 动态证书选择

2.1 功能概述

在 SSL 握手前执行 Lua 代码,动态选择证书。常用于:

  • SNI 多域名证书选择
  • 动态证书加载
  • Let's Encrypt 自动证书

2.2 OpenSSL 回调集成

int ngx_http_lua_ssl_cert_handler(ngx_ssl_conn_t *ssl_conn, void *data)
{
    // 1. 获取连接上下文
    // 2. 创建 fake connection/request
    // 3. 调用 Lua handler
    // 4. 返回结果 (1=成功, 0=失败)
}

2.3 FFI API

函数 功能
ngx_http_lua_ffi_ssl_clear_certs 清除当前证书
ngx_http_lua_ffi_set_cert 设置证书链
ngx_http_lua_ffi_set_priv_key 设置私钥
ngx_http_lua_ffi_ssl_server_name 获取 SNI 服务器名
ngx_http_lua_ffi_ssl_raw_server_addr 获取服务器地址
ngx_http_lua_ffi_ssl_client_random 获取客户端随机数
ngx_http_lua_ffi_ssl_verify_client 启用客户端证书验证

2.4 证书解析 API

local ssl = require "ngx.ssl"

-- PEM 转 DER
local der_cert, err = ssl.cert_pem_to_der(pem_cert)
local der_key, err = ssl.priv_key_pem_to_der(pem_key)

-- 设置证书
local ok, err = ssl.set_der_cert(der_cert)
local ok, err = ssl.set_der_priv_key(der_key)

2.5 使用示例

server {
    listen 443 ssl;
    server_name ~^(.+)\.example\.com$;

    ssl_certificate_by_lua_block {
        local ssl = require "ngx.ssl"

        -- 获取 SNI
        local server_name, err = ssl.server_name()
        if not server_name then
            ngx.log(ngx.ERR, "no SNI")
            return ngx.exit(ngx.ERROR)
        end

        -- 动态加载证书
        local cert = load_cert_from_redis(server_name)
        if cert then
            ssl.set_der_cert(cert.der_cert)
            ssl.set_der_priv_key(cert.der_key)
        end
    }

    ssl_certificate /fallback.crt;
    ssl_certificate_key /fallback.key;
}

三、SSL Session 缓存

3.1 ssl_session_store_by_lua

存储 Session 到外部存储。

ssl_session_store_by_lua_block {
    local ssl_session = require "ngx.ssl.session"

    local id, err = ssl_session.get_session_id()
    local data, err = ssl_session.get_serialized_session()

    -- 存储到 Redis
    local redis = require "resty.redis"
    local red = redis:new()
    red:connect("127.0.0.1", 6379)
    red:setex("ssl:sess:" .. id, 3600, data)
}

3.2 ssl_session_fetch_by_lua

从外部存储获取 Session。

ssl_session_fetch_by_lua_block {
    local ssl_session = require "ngx.ssl.session"

    local id, err = ssl_session.get_session_id()

    local redis = require "resty.redis"
    local red = redis:new()
    red:connect("127.0.0.1", 6379)
    local data = red:get("ssl:sess:" .. id)

    if data then
        ssl_session.set_serialized_session(data)
    end
}

3.3 异步支持

Session fetch 支持异步操作:

#ifdef SSL_ERROR_PENDING_SESSION
return SSL_magic_pending_session_ptr();  // 挂起,等待异步完成
#endif

四、ssl_client_hello_by_lua

4.1 功能概述

在 Client Hello 消息处理后执行,可用于:

  • 基于客户端能力选择协议
  • 访问控制
  • 早期拒绝

4.2 要求

  • OpenSSL 1.1.1+
  • 使用 SSL_ERROR_WANT_CLIENT_HELLO_CB 回调机制

4.3 使用示例

ssl_client_hello_by_lua_block {
    local ssl = require "ngx.ssl"

    -- 获取支持的协议版本
    local version = ssl.get_tls1_version()

    -- 拒绝旧版 TLS
    if version < 0x0303 then  -- TLS 1.2
        return ngx.exit(ngx.ERROR)
    end
}

五、Socket SSL

5.1 SSL 握手

local sock = ngx.socket.tcp()
sock:connect("example.com", 443)

-- SSL 握手
local session, err = sock:sslhandshake(
    nil,           -- session 复用对象
    "example.com", -- SNI
    true           -- 验证证书
)

if not session then
    ngx.log(ngx.ERR, "SSL handshake failed: ", err)
    return
end

5.2 SSL 配置指令

指令 说明
lua_ssl_protocols SSL 协议版本
lua_ssl_ciphers 加密套件
lua_ssl_verify_depth 验证深度
lua_ssl_trusted_certificate CA 证书

六、Proxy SSL

6.1 proxy_ssl_certificate_by_lua

动态设置代理 SSL 客户端证书。

6.2 proxy_ssl_verify_by_lua

自定义代理 SSL 验证。


七、FFI API 参考

证书操作

// PEM 解析
void *ngx_http_lua_ffi_parse_pem_cert(const u_char *pem, size_t len, char **err);
void *ngx_http_lua_ffi_parse_pem_priv_key(const u_char *pem, size_t len, char **err);

// DER 解析
void *ngx_http_lua_ffi_parse_der_cert(const char *data, size_t len, char **err);
void *ngx_http_lua_ffi_parse_der_priv_key(const char *data, size_t len, char **err);

// 释放
void ngx_http_lua_ffi_free_cert(void *cdata);
void ngx_http_lua_ffi_free_priv_key(void *cdata);

SSL 信息获取

int ngx_http_lua_ffi_ssl_server_name(ngx_http_request_t *r,
    const char **name, size_t *namelen, char **err);

int ngx_http_lua_ffi_ssl_raw_server_addr(ngx_http_request_t *r,
    const char **addr, size_t *addrlen, int *port, char **err);

int ngx_http_lua_ffi_ssl_client_random(ngx_http_request_t *r,
    unsigned char *out, size_t *outlen, char **err);