Nginx

即使 HTTP HOST 標頭與 SNI 不同,Nginx 也會以 200 響應

  • April 21, 2018

我剛剛開始學習 nginx 和 SSL,並且一直在研究不同的配置。我有兩個伺服器塊,如下所示:

server{
   listen 443 ssl http2;
   server_name www.a.com;
   ssl_certificate a.crt;
   ssl_certificate_key a.key;
   ....
}
server{
   listen 443 ssl ;
   server_name www.b.com;
   ssl_certificate b.crt;
   ssl_certificate_key b.key;
   ....
}

在使用 www.a.com 作為我的 SNI 通過 openssl s_client 連接到 nginx 後,我使用 Host: www.b.com 發送了一個 GET 請求,它仍然有效。這是預期的嗎?有人可以幫我理解 nginx 的行為嗎?

HTTP 連接歸根結底只是一個 TCP 連接。所以上面的內容實際上適用於 HTTP 連接(即,如果你連接到www.a.com,你實際上是連接到一個 IP 地址而不是www.a.com,所以它實際上很好並且預期該連接能夠www.b.com的地址請求)。

對於HTTPS,就像你說你正在使用的那樣,它有點不太清楚……

對於 HTTP/1.1,HTTP Over TLS RFCHypertext Transfer Protocol (HTTP/1.1): Message Syntax and Routing RFC中沒有任何內容來說明應該如何處理,因為 SNI 是在之後添加的 HTTP 的非強制性擴展(事實上,順便說一句,這是繞過客戶端的一種方式 - 例如 XP 上的 IE8 - 如果兩個虛擬主機使用相同的證書,則可以在基於該證書協商 TLS 會話之後使用適當的連接作為由預設主機提供)。然而,SNI RFC 明確指出伺服器必須檢查這是否相同,因此當給出的伺服器名稱與主機不同時,您所觀察到的內容是不正確的(感謝 Michael Hampton 指出這一點,因為我最初錯過了這個)。

HTTP/2 在這方面更清楚,實際上確實允許在某些條件下重用連接,並且有這樣的說法

只要源伺服器具有權威性,就可以重用連接(第 10.1 節)。對於沒有 TLS 的 TCP 連接,這取決於解析到相同 IP 地址的主機。

對於 https 資源,連接重用還取決於是否擁有對 URI 中的主機有效的證書。伺服器提供的證書必須滿足客戶端在為 URI 中的主機建立新的 TLS 連接時將執行的任何檢查。

源伺服器可能提供具有多個 subjectAltName 屬性或帶有萬用字元的名稱的證書,其中一個對 URI 中的權限有效。例如,subjectAltName 為 *.example.com 的證書可能允許對以https://a.example.com/https://b.example.com/開頭的 URI 的請求使用相同的連接。

因此,如果 a.crt 還包括在主題備用名稱欄位中包含www.b.com,那麼上面在 HTTP/2 下實際上是可以的,儘管在 HTTP/1.1 下不是。

但是,可以肯定的是,當 a.crt 絕對不涵蓋www.b.com並且這聽起來確實像一個錯誤並且可能存在安全風險時,我已經重複了您的觀察,因為對一個虛擬主機的請求可能是如果有人能夠注入無效的主機標頭(幸運的是瀏覽器並不容易做到這一點 - 所以誠然我無法證明這一點),則由另一個虛擬主機讀取(儘管無法訪問用於解密消息的密鑰)。這可能會將 cookie 或其他資訊洩漏到輔助伺服器。

我已經向 nginx 安全團隊提出了這個問題,他們說這不是 nginx 的安全漏洞,由客戶端來驗證證書,然後不要向他們應該通過該連接訪問的主機發送格式錯誤的請求. 我強烈不同意這一點,並說 HTTPS 的全部意義在於只允許有效的端點解密消息!所以我認為檢查應該同時在客戶端伺服器端進行,事實上,當時 TLS 工作組討論了這個確切的場景,SNI 是特定的,這就是為什麼將上述措辭添加到 RFC. 此外,nginx 安全團隊表示,在這種情況下,nginx 應該為兩個主機設置一個聯合證書(這對我來說毫無意義,因為嚴重限制了 nginx 中虛擬主機的實用性!),但如果 nginx 伺服器運營商真的想要限制這一點,那麼他們可以通過檢查$ssl_server_name變數來做到這一點(這對我來說意味著這是一個相對容易的檢查,預設情況下 nginx 可以做到!)。無論如何,這是他們的軟體,因此他們有權發表意見,但我不同意。

也有人指出,這種技術有時用於避免在稱為Domain Fronting的過程中進行審查。這很公平,但我認為應該明確啟用而不是預設允許。

順便說一句,Apache 並沒有這樣做,並且(正確地恕我直言)在 2.4.17 之前返回“400 Bad Request”,在 2.4.17 之後返回新的“421(錯誤定向請求)”——這是專門為此創建的新 HTTP 狀態程式碼情景

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