Nginx - 如何访问客户端证书的主题备用名称(SAN)字段

时间:2018-05-30 21:47:18

标签: nginx ssl-certificate x509 client-certificates

我有一个Nginx服务器,客户端使用包含特定CN和SAN的客户端证书发出请求。我希望能够提取该客户端证书的CN(通用名称)和SAN(主题备用名称)字段。

粗略的示例配置:

server {
listen 443 ssl;
ssl_client_certificate /etc/nginx/certs/client.crt;
ssl_verify_client on; #400 if request without valid cert

location / {
    root    /usr/share/nginx/html;

}
location /auth_test {
    # do something with the CN and SAN.
    # tried these embedded vars so far, to no avail
    return 200 "
    $ssl_client_s_dn 
    $ssl_server_name
    $ssl_client_escaped_cert
    $ssl_client_cert
    $ssl_client_raw_cert";
}
}

使用作为ngx_http_ssl_module模块一部分公开的嵌入变量,我可以访问DN(专有名称),因此可以访问CN等,但我似乎无法访问SAN。< / p>

是否有一些嵌入式var /其他模块/一般Nginx foo我失踪了?我可以访问原始证书,因此可以手动解码并提取它吗?

我真的宁愿在Nginx层执行此操作,而不是将证书传递到应用程序层并在那里执行。

任何帮助都非常感激。

5 个答案:

答案 0 :(得分:1)

您可以通过OpenResty + Lua-OpenSSL完成并解析原始证书以获取它。

请参阅:https://github.com/Seb35/nginx-ssl-variables/blob/master/COMPATIBILITY.md#ssl_client_s_dn_x509

就像这样:

local varibleName = string.match(require("openssl").x509.read(ngx.var.ssl_client_raw_cert):issuer():oneline(),"/C=([^/]+)")

答案 1 :(得分:1)

我不是lua专家,但是这就是我的工作:

local openssl = require('openssl')

dnsNames = {}
for k,v in pairs(openssl.x509.read(ngx.var.ssl_client_raw_cert):extensions()) do
    for k1,v1 in pairs(v:info()) do
        if(type(v1)=='table') then
            for k2,v2 in pairs(v1) do
                if(type(v2)=='table') then
                    for k3,v3 in pairs(v2) do
                        if(k3=='dNSName') then
                            table.insert(dnsNames, v3:toprint())
                        end
                    end
                end
            end
        end
    end
end
ngx.say(table.concat(dnsNames, ':'))

答案 2 :(得分:0)

当我尝试通过上游服务器检索“主题DN”时,遇到了同样的问题。 有人可能会发现以下建议很有用。因此,有一个访问 诸如(“主题DN”等)的字段-您必须查看link1。在它旁边,我必须将这些数据输入到请求标头中,因此我已经通过'proxy_set_header'(link2)完成了此操作。可能不需要任何额外的Nginx扩展(无需使用--modules重建它们,只需使用默认模块即可​​)

答案 3 :(得分:0)

您可以使用Nginx内置的map提取它们,例如对于CN:

map $ssl_client_s_dn $ssl_client_s_dn_cn {
    default "";
    ~,CN=(?<CN>[^,]+) $CN;
}

答案 4 :(得分:0)

这是一个如何从客户端证书扩展中提取 URI 值然后作为标头转发到上游服务器的示例。例如,这在实施 WebID over TLS 身份验证时很有用。

location / {
    proxy_pass http://upstream;

    set_by_lua_block $webid_uri {
        local openssl = require('openssl')

        webIDs = {}
        for k,v in pairs(openssl.x509.read(ngx.var.ssl_client_raw_cert):extensions()) do
            for k1,v1 in pairs(v:info()) do
                if(type(v1)=='table') then
                    for k2,v2 in pairs(v1) do
                        if(type(v2)=='table') then
                            for k3,v3 in pairs(v2) do
                                if(k3=='uniformResourceIdentifier') then
                                    table.insert(webIDs, v3:data())
                                end
                            end
                        end
                    end
                end
            end
        end

        return webIDs[1]
    }

    proxy_set_header X-WebID-URI $webid_uri;
}

如果可以改进,请告诉我。