You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Nginx如何访问客户端证书的Subject Alternative Name(SAN)字段

搞定Nginx提取客户端证书CN和SAN的问题

嘿,我来帮你解决这个痛点!Nginx原生确实没有直接获取SAN的变量,但咱们有几种靠谱的方法可以在Nginx层面搞定,不用把证书丢给后端应用处理。

一、提取CN字段(原生方案,零额外模块)

首先是CN,你可以利用$ssl_client_s_dn变量,再配合Nginx的map模块精准提取CN部分,不用搞复杂的东西:

先在http块里定义一个map规则,专门从DN里抠出CN:

http {
    map $ssl_client_s_dn $ssl_client_cn {
        default "";
        # 用正则匹配CN=后面的内容,直到遇到/或者结尾
        ~*CN=(?<cn>[^/]+) $cn;
    }
}

之后在你的/auth_test location里就能直接用$ssl_client_cn了,比如:

location /auth_test {
    return 200 "客户端证书CN: $ssl_client_cn";
}

这个正则会自动匹配DN里的CN=xxx部分,把xxx提取出来,完美解决CN的问题。

二、提取SAN字段(两种可行方案)

遗憾的是Nginx原生没有内置变量直接返回SAN,所以得用点额外手段,这里给你两种方案,按需选择:

方案1:用Lua模块(推荐,性能更优)

如果你的Nginx是OpenResty,或者已经编译安装了ngx_http_lua_module,那用Lua来解析证书是最好的选择,性能比调用外部命令好很多。

直接在location里写Lua代码,利用$ssl_client_raw_cert拿到原始证书,再调用openssl命令解析SAN:

location /auth_test {
    content_by_lua_block {
        -- 先拿到原始证书内容
        local cert = ngx.var.ssl_client_raw_cert
        if not cert then
            ngx.say("没有提供有效的客户端证书")
            return
        end

        -- 解析SAN字段
        local san_handle = io.popen("echo '" .. cert .. "' | openssl x509 -noout -text | grep -A 1 'Subject Alternative Name' | grep -v 'Subject Alternative Name'")
        local san = san_handle:read("*a")
        san_handle:close()

        -- 直接用前面定义好的$ssl_client_cn变量即可
        local cn = ngx.var.ssl_client_cn

        ngx.say("客户端证书CN: ", cn)
        ngx.say("客户端证书SAN: ", san)
    }
}

要是你用的是纯Nginx,记得先编译安装lua-nginx-module,同时确保服务器上有openssl命令。

方案2:调用外部Shell脚本(应急方案,性能一般)

如果不想折腾Lua模块,也可以写个简单的Shell脚本,让Nginx调用它来解析证书,但这种方式每次请求都会启动子进程,高并发场景不太推荐,适合小流量场景应急:

第一步,写个脚本/usr/local/bin/extract_cert_info.sh:

#!/bin/bash
# 读取输入的证书内容
CERT=$(cat)
# 提取CN
CN=$(echo "$CERT" | openssl x509 -noout -subject | grep -oP 'CN=\K[^,]+')
# 提取SAN
SAN=$(echo "$CERT" | openssl x509 -noout -text | grep -A 1 'Subject Alternative Name' | grep -v 'Subject Alternative Name')
# 输出结果
echo "客户端证书CN: $CN"
echo "客户端证书SAN: $SAN"

给脚本加执行权限:chmod +x /usr/local/bin/extract_cert_info.sh

然后在Nginx配置里这样写:

location /auth_test {
    if ($ssl_client_raw_cert) {
        # 先读取请求体里的证书内容
        echo_read_request_body;
        # 调用脚本解析
        exec /usr/local/bin/extract_cert_info.sh;
    }
    return 400 "未提供有效客户端证书";
}

这个方法简单,但性能确实不如Lua方案,谨慎使用。

三、一些注意事项

  • 一定要确保ssl_verify_client设置为on或者optional,不然Nginx不会验证客户端证书,也不会生成那些证书相关的变量。
  • $ssl_client_raw_cert是PEM格式的原始证书,处理的时候别搞乱格式,不然openssl解析会失败。
  • 用Lua方案的话,建议加个缓存(比如用ngx.shared.dict),把解析过的证书信息存起来,避免每次请求都调用openssl,进一步提升性能。

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 08:24:58