Nginx - how to access Client Certificate's Subject Alternative Name (SAN) field

不羁的心 提交于 2020-05-26 09:46:24

问题


I have an Nginx server which clients make requests to with a Client certificate containing a specific CN and SAN. I want to be able to extract the CN (Common Name) and SAN (Subject Alternative Names) fields of that client cert.

rough example config:

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";
}
}

Using the embedded variables exposed as part of the ngx_http_ssl_module module I can access the DN (Distinguished Name) and therefore CN etc but I don't seem to be able to get access to the SAN.

Is there some embedded var / other module / general Nginx foo I'm missing? I can access the raw cert, so is it possible to decode that manually and extract it?

I'd really rather do this at the Nginx layer as opposed to passing the cert down to the application layer and doing it there.

Any help much appreciated.


回答1:


You can do it through OpenResty + Lua-OpenSSL and parse the raw certificate to get it.

Refer this: https://github.com/Seb35/nginx-ssl-variables/blob/master/COMPATIBILITY.md#ssl_client_s_dn_x509

Just like this:

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



回答2:


You can extract them with the Nginx-builtin map, e.g. for CN:

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



回答3:


I'm not a lua expert, but here's what I got working:

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, ':'))



回答4:


Had the same problem, when I try to retrieve "subject DN" by a upstream server. Someone might find the following advice useful. Thus, there is an access to such fields as ("subject DN" an so on) - you have to look at link1. Beside it, I had to through this data into the request header, so I've done it via 'proxy_set_header' (link2). It was possible without any extra Nginx extension (there is not need to rebuild them with --modules, just default modules)



来源:https://stackoverflow.com/questions/50613782/nginx-how-to-access-client-certificates-subject-alternative-name-san-field

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!