You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

开发Nginx模块:如何在C代码中获取客户端证书并提取CN用于认证

在Nginx自定义C模块中获取客户端证书并提取CN的解决方案

首先得确认你的Nginx基础配置已经正确开启了客户端证书验证——这是模块能拿到证书的前提:

server {
    listen 443 ssl;
    ssl_certificate /path/to/server.crt;
    ssl_certificate_key /path/to/server.key;
    ssl_client_certificate /path/to/ca.crt; # 指定信任的CA证书
    ssl_verify_client optional; # 根据业务需求选on/optional/optional_no_ca
    ssl_verify_depth 2; # 设置证书链的验证深度

    # 你的其他站点配置...
}

接下来是核心的C模块代码实现步骤:

1. 获取客户端证书指针

在你的模块处理函数(比如ngx_http_xxx_handler)里,通过请求结构体逐层拿到OpenSSL的X509证书对象:

#include <ngx_http.h>
#include <openssl/x509.h>
#include <openssl/x509v3.h>

static ngx_int_t ngx_http_my_module_handler(ngx_http_request_t *r) {
    ngx_ssl_connection_t *ssl_conn;
    X509 *client_cert;

    // 先检查当前连接是否启用了SSL
    if (r->connection->ssl == NULL) {
        return ngx_http_internal_server_error(r);
    }

    ssl_conn = r->connection->ssl;
    client_cert = ssl_conn->peer_cert;

    // 检查客户端是否提供了有效证书
    if (client_cert == NULL) {
        // 这里可以根据业务逻辑处理,比如返回403或者允许无证书请求
        return ngx_http_forbidden(r);
    }

    // 下一步提取CN字段...

2. 从证书中提取通用名称(CN)

借助OpenSSL的API,从证书的主题名称中提取CN字段:

X509_NAME *subject_name;
    char cn_buf[256] = {0};
    int cn_len;

    subject_name = X509_get_subject_name(client_cert);
    if (subject_name == NULL) {
        return ngx_http_internal_server_error(r);
    }

    // NID_commonName是OpenSSL预定义的通用名称标识符
    cn_len = X509_NAME_get_text_by_NID(subject_name, NID_commonName, cn_buf, sizeof(cn_buf)-1);
    if (cn_len <= 0) {
        // 证书中没有CN字段,按业务需求处理错误
        return ngx_http_forbidden(r);
    }

    // 现在cn_buf里就是证书的CN了,你可以用它做后续的认证逻辑
    ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, "Client CN: %s", cn_buf);

    // 你的业务逻辑代码...
    return ngx_http_ok(r);
}

3. 编译模块的注意事项

因为用到了OpenSSL的API,编译模块时必须确保链接OpenSSL库:

  • 在模块的config文件里,添加OpenSSL相关依赖:
ngx_addon_name=ngx_http_my_module
HTTP_MODULES="$HTTP_MODULES ngx_http_my_module"
NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/ngx_http_my_module.c"

# 链接OpenSSL库
CORE_LIBS="$CORE_LIBS -lssl -lcrypto"
  • 编译Nginx时要带上--with-openssl参数(如果你的Nginx不是默认编译OpenSSL的话)。

为什么不推荐用响应头的方法?

你之前找到的add-header X-Client-Cert $ssl_client_certificate方法,本质是把证书内容返回给客户端,这不仅存在证书信息泄露的风险,而且对你的认证需求来说完全绕了弯路——直接在模块内处理证书,既能避免不必要的信息暴露,又能更高效地完成认证逻辑。

内容的提问来源于stack exchange,提问作者user1918858

火山引擎 最新活动