为特定 nginx 虚拟服务器覆盖“SSL 客户端:否”

为特定 nginx 虚拟服务器覆盖“SSL 客户端:否”

我有一群客户端(太多了,无法轻易改造),每个客户端都持有一个证书(由我无法控制的非标准 CA 签名;我只是生成了 CSR)。

现在我需要设置一个“安全”的 Web 服务,其中服务器以通常的 ssl(https)方式进行识别,并且应使用其证书进行识别客户端(主题已经保存了我需要唯一识别客户端的所有信息)。

不幸的是,在签署过程中几乎所有的“目的”标志都被清除了:

openssl x509 -in 57EMM020001.cer -noout -purpose 
Certificate purposes:
SSL client : No
SSL client CA : No
SSL server : No
SSL server CA : No
Netscape SSL server : No
Netscape SSL server CA : No
S/MIME signing : Yes
S/MIME signing CA : No
S/MIME encryption : No
S/MIME encryption CA : No
CRL signing : No
CRL signing CA : No
Any Purpose : Yes
Any Purpose CA : Yes
OCSP helper : Yes
OCSP helper CA : No
Time Stamp signing : No
Time Stamp signing CA : No

我认为“400 SSL 证书错误”的“罪魁祸首”是第一个:“SSL 客户端:否”。

有什么办法可以告诉我的本地 nginx 服务器(我对它有完全控制权)忽略这些设置?

我完全理解这总体来说是“不好的”,因为如果证书不是为特定目的而生成的……那么,它就不应该用于该目的!但这是我的、非常具体的服务器,我觉得我有权决定我信任谁。

有没有什么方法可以说服 nginx 以稍微宽松的方式做事?

我当前(不工作)的设置非常简单:

server {
    listen 443 ssl;

    resolver 127.0.0.1 8.8.8.8;
    set $backend "http://localhost:5000";

    server_name updates.example.com;

    ssl_certificate /etc/ssl/certs/server.pem;
    ssl_certificate_key /etc/ssl/private/server.key;

    ssl_client_certificate /etc/ssl/certs/CAroot.cer;
    ssl_verify_client on;

    location / {
        proxy_connect_timeout   60;
        proxy_read_timeout      60;
        proxy_send_timeout      60;
        proxy_intercept_errors  off;
        proxy_http_version      1.1;
        proxy_set_header        Host               $http_host;
        proxy_set_header        X-Real-IP          $remote_addr;
        proxy_set_header        X-Forwarded-For    $proxy_add_x_forwarded_for;
        proxy_set_header        X-Forwarded-Proto  $scheme;
        proxy_set_header        X-Client-Subject   $ssl_client_s_dn;
        proxy_pass $backend;
    }    
}

我当然检查过了:

openssl verify -verbose -CAfile /etc/ssl/certs/CAroot.cer 57EMM020001.cer 
57EMM020001.cer: OK

提前致谢

答案1

我找到了一个可行的解决方案,但它并不是很优雅,所以我会暂时不接受它,希望有人能想出更好的解决方案。

删除ssl_client_certificate并切换到ssl_verify_client optional_no_ca实际上会获取客户端证书,但它不会尝试检查它,因此后端可以自主进行检查。

我当前的 nginx 设置是:

server {
    listen 443 ssl;

    resolver 127.0.0.1 8.8.8.8;
    set $backend "http://localhost:5000";

    server_name updates.example.com;

    ssl_certificate /etc/ssl/certs/server.pem;
    ssl_certificate_key /etc/ssl/private/server.key;

    ssl_verify_client optional_no_ca;

    location / {
        proxy_connect_timeout   60;
        proxy_read_timeout      60;
        proxy_send_timeout      60;
        proxy_intercept_errors  off;
        proxy_http_version      1.1;
        proxy_set_header        Host               $http_host;
        proxy_set_header        X-Real-IP          $remote_addr;
        proxy_set_header        X-Forwarded-For    $proxy_add_x_forwarded_for;
        proxy_set_header        X-Forwarded-Proto  $scheme;
        proxy_set_header        X-Client-Subject   $ssl_client_s_dn;
        proxy_set_header        X-Client-Cert      $ssl_client_cert;
        proxy_pass $backend;
    }
}

后端(简单的 python/flask 安装)包括:

def get_id(headers):
    cer = headers.get('X-Client-Cert')
    with NamedTemporaryFile('w+') as ntf:
        for lin in cer.splitlines():
            ntf.write(lin.strip())
            ntf.write('\n')
        ntf.flush()
        p = run(['openssl', 'verify', '-CAfile', cafile, ntf.name])
    if p.returncode == 0:
        m = search(r'/CN=([~/]+)', headers.get('X-Client-Subject'))
        if m:
            return m.group(1)
    return None

相关内容