2025年9月25日: PostgreSQL 18 釋出!
支援的版本:當前 (18) / 17 / 16 / 15 / 14 / 13
開發版本:開發版
不支援的版本:12 / 11 / 10 / 9.6 / 9.5 / 9.4 / 9.3 / 9.2 / 9.1 / 9.0 / 8.4 / 8.3 / 8.2 / 8.1 / 8.0

32.19. SSL 支援 #

PostgreSQL 原生支援使用SSL連線來加密客戶端/伺服器通訊,使用TLS協議以增強安全性。有關伺服器端功能的詳細資訊,請參閱第 18.9 節SSL功能。

libpq 讀取系統範圍的 OpenSSL 配置檔案。預設情況下,此檔名為 openssl.cnf,位於 openssl version -d 報告的目錄中。可以透過將環境變數 OPENSSL_CONF 設定為所需配置檔案的名稱來覆蓋此預設值。

32.19.1. 客戶端驗證伺服器證書 #

預設情況下,PostgreSQL 不會執行任何伺服器證書驗證。這意味著,如果不讓客戶端知道,就可以偽造伺服器身份(例如,透過修改 DNS 記錄或接管伺服器 IP 地址)。為了防止偽造,客戶端必須能夠透過信任鏈來驗證伺服器的身份。信任鏈的建立方式是將一個根(自簽名)證書頒發機構(CA) 證書放在一臺計算機上,並將一個由根證書簽名的葉子證書放在另一臺計算機上。也可以使用一個由根證書籤名並簽名葉子證書的“中間”證書。

為了讓客戶端能夠驗證伺服器的身份,請將根證書放在客戶端,並將由根證書籤名的葉子證書放在伺服器上。為了讓伺服器能夠驗證客戶端的身份,請將根證書放在伺服器上,並將由根證書籤名的葉子證書放在客戶端。一個或多箇中間證書(通常與葉子證書一起儲存)也可以用來將葉子證書連結到根證書。

一旦建立了信任鏈,客戶端就有兩種方法來驗證伺服器傳送的葉子證書。如果引數 sslmode 設定為 verify-ca,libpq 將透過檢查證書鏈到客戶端儲存的根證書來驗證伺服器是否可信。如果 sslmode 設定為 verify-full,libpq 將驗證伺服器主機名是否與伺服器證書中儲存的名稱匹配。如果伺服器證書無法驗證,SSL 連線將失敗。verify-full 在大多數安全敏感環境中推薦使用。

verify-full 模式下,主機名將與證書的主題備用名稱(SAN)屬性進行匹配,如果不存在 dNSName 型別的 SAN,則與通用名稱(Common Name)屬性進行匹配。如果證書的名稱屬性以星號(*)開頭,則星號將被視為萬用字元,它將匹配除點(.)之外的所有字元。這意味著證書將不匹配子域。如果使用 IP 地址而不是主機名進行連線,IP 地址將與 iPAddressdNSName 型別的 SAN 進行匹配(不執行任何 DNS 查詢)。如果沒有 iPAddress SAN 且沒有匹配的 dNSName SAN,則主機 IP 地址將與通用名稱屬性進行匹配。

注意

為了向後相容 PostgreSQL 的早期版本,主機 IP 地址的驗證方式與 RFC 6125 不同。主機 IP 地址始終與 dNSName SAN 以及 iPAddress SAN 進行匹配,並且在不存在相關 SAN 時可以與通用名稱屬性進行匹配。

要允許伺服器證書驗證,必須將一個或多個根證書放在使用者主目錄下的 ~/.postgresql/root.crt 檔案中。(在 Microsoft Windows 上,檔名為 %APPDATA%\postgresql\root.crt。)如果需要將伺服器傳送的證書鏈連結到客戶端儲存的根證書,也應將中間證書新增到該檔案中。

如果檔案 ~/.postgresql/root.crl 存在(Microsoft Windows 上為 %APPDATA%\postgresql\root.crl),也將檢查證書吊銷列表(CRL)條目。

可以透過設定連線引數 sslrootcertsslcrl 或環境變數 PGSSLROOTCERTPGSSLCRL 來更改根證書檔案和 CRL 的位置。還可以使用 sslcrldir 或環境變數 PGSSLCRLDIR 來指定包含 CRL 檔案的目錄。

注意

為了向後相容 PostgreSQL 的早期版本,如果存在根 CA 檔案,sslmode=require 的行為將與 verify-ca 相同,這意味著伺服器證書將根據 CA 進行驗證。不鼓勵依賴此行為,需要證書驗證的應用程式應始終使用 verify-caverify-full

32.19.2. 客戶端證書 #

如果伺服器嘗試透過請求客戶端的葉子證書來驗證客戶端身份,libpq 將傳送儲存在使用者主目錄下的 ~/.postgresql/postgresql.crt 檔案中的證書。證書必須連結到伺服器信任的根證書。必須存在一個匹配的私鑰檔案 ~/.postgresql/postgresql.key。在 Microsoft Windows 上,這些檔案的名稱是 %APPDATA%\postgresql\postgresql.crt%APPDATA%\postgresql\postgresql.key。可以透過連線引數 sslcertsslkey,或環境變數 PGSSLCERTPGSSLKEY 來覆蓋證書和金鑰檔案的位置。

在 Unix 系統上,私鑰檔案的許可權必須禁止任何對世界或組的訪問;透過 chmod 0600 ~/.postgresql/postgresql.key 等命令實現。或者,檔案可以由 root 所有並具有組讀取許可權(即 0640 許可權)。這種設定適用於由作業系統管理證書和金鑰檔案的安裝。然後,libpq 的使用者應成為有權訪問這些證書和金鑰檔案的組的成員。(在 Microsoft Windows 上,沒有檔案許可權檢查,因為 %APPDATA%\postgresql 目錄被假定為安全的。)

postgresql.crt 中的第一個證書必須是客戶端證書,因為它必須與客戶端的私鑰匹配。可以選擇將“中間”證書附加到檔案中——這樣做可以避免在伺服器上儲存中間證書(ssl_ca_file)。

證書和金鑰可以是 PEM 或 ASN.1 DER 格式。

金鑰可以以明文形式儲存,或者使用 OpenSSL 支援的任何演算法(如 AES-128)用密碼短語加密。如果金鑰是加密儲存的,則可以在 sslpassword 連線選項中提供密碼短語。如果提供了加密金鑰並且 sslpassword 選項缺失或為空,如果存在 TTY,OpenSSL 將透過 Enter PEM pass phrase: 提示互動式地提示輸入密碼。應用程式可以透過提供自己的金鑰密碼回撥來覆蓋客戶端證書提示和 sslpassword 引數的處理;請參閱 PQsetSSLKeyPassHook_OpenSSL

有關建立證書的說明,請參閱第 18.9.5 節

32.19.3. 不同模式下提供的保護 #

引數 sslmode 的不同值提供不同級別的保護。SSL 可以提供針對三種類型攻擊的保護:

竊聽

如果第三方能夠檢查客戶端和伺服器之間的網路流量,它可以讀取連線資訊(包括使用者名稱和密碼)以及傳遞的資料。SSL使用加密來防止這種情況。

中間人(MITM)

如果第三方能夠修改資料在客戶端和伺服器之間傳遞,它可以假裝是伺服器,因此即使資料已加密也能看到和修改資料。然後,第三方可以將連線資訊和資料轉發給原始伺服器,使得無法檢測到此攻擊。常見的攻擊方式包括 DNS 投毒和地址劫持,即客戶端被導向了非預期的伺服器。還有其他幾種攻擊方法可以實現此目的。SSL透過向客戶端進行身份驗證來防止這種情況,透過證書驗證。

冒充

如果第三方可以冒充合法客戶端,它就可以簡單地訪問本不應訪問的資料。通常這可以透過不安全的密碼管理來實現。SSL透過客戶端證書來防止這種情況,確保只有持有有效證書的人才能訪問伺服器。

要使連線被認為是 SSL 安全的,必須在連線建立之前在客戶端和伺服器上都配置 SSL 使用。如果僅在伺服器上配置,客戶端可能會在知道伺服器需要高安全性之前就傳送敏感資訊(例如,密碼)。在 libpq 中,可以透過將 sslmode 引數設定為 verify-fullverify-ca,併為系統提供一個用於驗證的根證書來確保安全連線。這類似於使用 httpsURL進行加密的網路瀏覽。

一旦伺服器透過身份驗證,客戶端就可以傳遞敏感資料。這意味著直到此時,客戶端都不需要知道證書是否將用於身份驗證,因此可以在伺服器配置中僅指定這一點是安全的。

全部SSL選項會產生加密和金鑰交換形式的開銷,因此在效能和安全性之間必須進行權衡。表 32.1 說明了不同 sslmode 值所能防禦的風險,以及它們在安全性和開銷方面的宣告。

表 32.1. SSL 模式描述

sslmode 竊聽保護 MITM保護 宣告
disable 我不在乎安全,也不想支付加密的開銷。
allow 可能 我不在乎安全,但如果伺服器堅持,我願意支付加密的開銷。
prefer 可能 我不在乎加密,但我希望在伺服器支援的情況下支付加密的開銷。
require 我希望我的資料被加密,並且我接受開銷。我相信網路會確保我始終連線到我想要的伺服器。
verify-ca 取決於 CA 策略 我希望我的資料被加密,並且我接受開銷。我希望確保我連線到一個我信任的伺服器。
verify-full 我希望我的資料被加密,並且我接受開銷。我希望確保我連線到一個我信任的伺服器,並且它就是我指定的伺服器。

verify-ca 和 `verify-full` 之間的區別取決於根CA的策略。如果使用公共CA,`verify-ca` 允許連線到別人可能已註冊到CA的伺服器。在這種情況下,應始終使用 `verify-full`。如果使用本地CA,甚至自簽名證書,使用 `verify-ca` 通常也足夠安全。

sslmode 的預設值是 prefer。如表中所示,從安全形度來看,這沒有任何意義,它只會在可能的情況下承諾效能開銷。它僅作為預設值提供以實現向後相容,不建議在安全部署中使用。

32.19.4. SSL 客戶端檔案使用 #

表 32.2 總結了與客戶端 SSL 設定相關的檔案的資訊。

表 32.2. Libpq/Client SSL 檔案使用

檔案 目錄 效果
~/.postgresql/postgresql.crt 客戶端證書 傳送到伺服器
~/.postgresql/postgresql.key 客戶端私鑰 證明客戶端證書由所有者傳送;不表示證書所有者值得信任
~/.postgresql/root.crt 受信任的證書頒發機構 檢查伺服器證書是否由受信任的證書頒發機構簽名
~/.postgresql/root.crl 證書頒發機構吊銷的證書 伺服器證書不得在此列表中

32.19.5. SSL 庫初始化 #

需要與舊版 PostgreSQL(使用 OpenSSL 1.0.2 或更早版本)相容的應用程式在使用 SSL 庫之前需要初始化該庫。初始化 libssl 和/或 libcrypto 庫的應用程式應呼叫 PQinitOpenSSL 來告知 libpq libssl 和/或 libcrypto 庫已被您的應用程式初始化,這樣 libpq 就不會再次初始化這些庫。但是,在使用 OpenSSL 1.1.0 或更高版本時,不需要這樣做,因為重複初始化不再有問題。

有關其使用方法的詳細資訊,請參閱您正在針對的 PostgreSQL 版本的文件。

PQinitOpenSSL #

允許應用程式選擇要初始化的安全庫。

void PQinitOpenSSL(int do_ssl, int do_crypto);

此函式已棄用,僅為向後相容而存在,它不執行任何操作。

PQinitSSL #

允許應用程式選擇要初始化的安全庫。

void PQinitSSL(int do_ssl);

此函式等同於 PQinitOpenSSL(do_ssl, do_ssl)。此函式已棄用,僅為向後相容而存在,它不執行任何操作。

PQinitSSLPQinitOpenSSL 被保留用於向後相容,但在 PostgreSQL 18 後不再需要。PQinitSSLPostgreSQL 8.0 起存在,而 PQinitOpenSSLPostgreSQL 8.4 中新增,因此對於需要與舊版 libpq 相容的應用程式,PQinitSSL 可能更可取。

提交更正

如果您在文件中看到任何不正確、與您對特定功能的使用體驗不符或需要進一步澄清的內容,請使用此表單報告文件問題。