Nginx
覆蓋特定 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
提前致謝
我找到了一個可行的解決方案,但這並不是很優雅,所以我會暫時不接受這個問題,希望有人能提出更好的解決方案。
刪除
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