Nginx

覆蓋特定 nginx 虛擬伺服器的“SSL 客戶端:否”

  • September 23, 2020

我有一堆客戶(太多而無法輕鬆改造),每個客戶都持有一個證書(由我無法控制的非標準 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

引用自:https://serverfault.com/questions/1035044