我有一群客户端(太多了,无法轻易改造),每个客户端都持有一个证书(由我无法控制的非标准 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