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

257 lines
5.6 KiB
Markdown

# 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 回调集成
```c
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
```lua
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 使用示例
```nginx
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 到外部存储。
```nginx
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。
```nginx
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 支持异步操作:
```c
#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 使用示例
```nginx
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 握手
```lua
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 参考
### 证书操作
```c
// 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 信息获取
```c
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);
```