PostgreSQL10.1手冊_部分IV.客戶端介面_第33章libpq-C庫_33.18.SSL支援

李博bluemind發表於2018-10-03

33.18. SSL 支援

PostgreSQL本地支援使用SSL 連線加密客戶端/伺服器通訊以提高安全性。關於伺服器端的SSL 功能詳見第 18.9 節

libpq讀取系統範圍的OpenSSL 配置檔案。預設情況下,這個檔案被命名為openssl.cnf並且存放在 openssl version -d報告的目錄中。可以通過設定環境變數 OPENSSL_CONF把這個預設值覆蓋為想要的配置檔案的名稱。

33.18.1. 伺服器證書的客戶端驗證

預設情況下,PostgreSQL將不會執行伺服器證書的任何驗證。 這意味著可以在不被客戶端知曉的情況下偽造伺服器身份 (例如通過修改一個 DNS 記錄或者接管伺服器的 IP 地址)。為了阻止哄騙, 必須使用SSL證書驗證。

如果引數sslmode被設定為verify-ca, libpq 將通過檢查證書鏈一直到一個可信的證書機構(CA) 來驗證伺服器是可信的。如果sslmode被設定為verify-full, libpq 將還會驗證伺服器主機名是否匹配它的證書。 如果伺服器證書不能被驗證,SSL 連線將失敗。在大部分對安全敏感的環境中, 建議使用verify-full

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

要允許伺服器證書驗證,一個或多個可信的CA必須被放置在使用者home目錄下的檔案 ~/.postgresql/root.crt中。如果中間CA出現在 root.crt中,該檔案必須也包含到它們的根CA的證書鏈 (在微軟 Windows 上該檔案被命名為%APPDATA%postgresql
oot.crt
)。

如果檔案~/.postgresql/root.crl存在 (微軟 Windows 上的%APPDATA%postgresql
oot.crl
), 也會檢查證書撤銷列表(CRL)項。

根證書檔案和 CRL 的位置可以通過設定連線引數sslrootcert和 sslcrl或環境變數PGSSLROOTCERTPGSSLCRL改變。

注意

為了與 PostgreSQL 的早期版本達到向後相容,如果存在一個根 CA 檔案,sslmode=require的行為將與 verify-ca相同,意味著伺服器證書根據 CA 驗證。 不鼓勵依賴這種行為,並且需要證書驗證的應用程式應該總是使用 verify-ca或者verify-full

33.18.2. 客戶端證書

如果伺服器要求一個可信的客戶端證書,libpq 將傳送使用者主目錄中~/.postgresql/postgresql.crt檔案儲存的證書。 該證書必須由一個受伺服器信任的證書機構(CA)簽發。 也必須存在一個匹配的私鑰檔案~/.postgresql/postgresql.key。 該私鑰檔案不允許全域性或組使用者的任何訪問,可以通過命令 chmod 0600 ~/.postgresql/postgresql.key實現。 在微軟 Windows 上這些檔案被命名為%APPDATA%postgresqlpostgresql.crt 和%APPDATA%postgresqlpostgresql.key,不會有特別的許可權檢查, 因為該目錄被假定為安全。證書和金鑰檔案的位置可以使用連線引數sslcert 和sslkey或者環境變數PGSSLCERTPGSSLKEY覆蓋。

在一些情況下,客戶端證書可以由中間證書機構簽名, 而不是由伺服器直接信任的證書機構。 要使用這樣一個證書,將簽發機構的證書加入到postgresql.crt檔案, 然後是它的上級機構的證書,並且一直到一個受伺服器信任的證書機構( 機構或者中間機構),即由該伺服器的 root.crt檔案中的一個證書籤發。

注意客戶端的~/.postgresql/root.crt 列出了被認為可信的能用於簽發伺服器證書的頂層 CA。 原則上不需要列出簽發客戶端證書的 CA, 大部分情況下這些 CA 也被信任可以用於伺服器證書。

33.18.3. 不同模式中提供的保護

sslmode引數的不同值提供了不同級別的保護。 SSL 能夠針對三類攻擊提供保護:

竊聽

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

中間人(MITM)

如果一個第三方能對客戶端和伺服器之間傳送的資料進行修改, 它就能假裝是伺服器並且因此能看見並且修改資料,即使這些資料已被加密。 然後第三方可以將連線資訊和資料傳送給原來的伺服器,使得它不可能檢測到攻擊。 這樣做的常用載體包括 DNS 中毒和地址劫持,藉此客戶端被定向到預期之外的不同的伺服器。 還有幾種其他的攻擊方式能夠完成這種攻擊。SSL 使用證書驗證讓客戶端認證伺服器,就可以阻止這種攻擊。

模仿

如果第三方可以偽裝成一個授權的客戶端, 那麼它能夠輕鬆訪問它本不能訪問的資料。通常這可以由不安全的口令管理所致。 SSL使用客戶端證書來阻止這種情況, 即確保只有持有合法證書的客戶才能訪問伺服器。

對於一個已知安全的連線,在連線被建立之前,必須在 客戶端和伺服器端都進行SSL配置。如果只在伺服器上配置, 客戶端在知道伺服器要求高安全性之前可能會結束髮送敏感資訊(例如口令)。 在 libpq 中,可以通過將sslmode引數設定為verify-full或 verify-ca來確保安全連線,並且為系統提供一個根證書用來驗證。 這類似於使用https URL進行加密網頁瀏覽。

一旦伺服器已經被認證,客戶端可以傳遞敏感資料。這意味著直到這一點, 客戶端都不需要知道是否證書將被用於認證,這樣只需要在伺服器配置中指定就比較安全。

所有SSL選項都帶來了加密和金鑰交換的開銷, 因此必須在效能和安全性之間做出平衡。表 33.1 說明不同sslmode值所保護的風險,以及關於安全和開銷所做出的宣告。

表 33.1. SSL 模式描述

sslmode 竊聽保護 MITM保護 宣告
disable 我不關心安全性,並且我不想承擔加密的開銷。
allow 可能 我不關心安全性,但如果伺服器堅持,我會承擔加密開銷 。
prefer 可能 我不關心加密,但如果伺服器支援,我希望承擔加密開銷。
require 我希望我的資料加密,我接受開銷。 我相信該網路將確保我始終連線到想要連線的伺服器。
verify-ca 取決於 CA-策略 我希望我的資料加密,我接受開銷。 我想要確保我連線到的是我信任的伺服器。
verify-full 我希望我的資料加密,我接受開銷。 我想要確保我連線到的是我信任的伺服器,並且就是我指定的那一個。

verify-caverify-full之間的區別取決於根CA的策略。 如果使用了一個公共CA,verify-ca允許連線到那些可能已經被 其他人註冊到該CA的伺服器。在這種情況下,總是應該使用verify-full。如果使用了一個本地CA或者甚至是一個自簽名的證書, 使用verify-ca通常就可以提供足夠的保護。

sslmode的預設值是prefer。如表中所示, 從安全形度來看這樣做是沒有意義的,並且它只承諾可能的效能開銷。 提供它作為預設值只是為了向後相容,在安全部署中不建議使用。

33.18.4. SSL 客戶端檔案使用

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

表 33.2. Libpq/客戶端 SSL 檔案用法

檔案 內容 影響
~/.postgresql/postgresql.crt 客戶端證書 由伺服器要求
~/.postgresql/postgresql.key 客戶端私鑰 證明由所有者傳送客戶端證書,並不表示證書所有者是可信的
~/.postgresql/root.crt 受信任的證書頒發機構 檢查伺服器證書是由一個可信的證書機構簽發
~/.postgresql/root.crl 被證書頒發機構撤銷的證書 伺服器證書必須不在這個列表中

33.18.5. SSL 庫初始化

如果你的應用初始化libssllibcrypto庫以及 libpq編譯為支援SSL,你應該呼叫 PQinitOpenSSL來告訴libpqlibssl 或libcrypto庫已經被你的應用初始化,這樣libpq 將不會再初始化這些庫。 關於 SSL API 詳見http://h71000.www7.hp.com/doc/83final/ba554_90007/ch04.html

PQinitOpenSSL

允許應用選擇要初始化哪個安全庫。

void PQinitOpenSSL(int do_ssl, int do_crypto);

do_ssl是非零時,libpq 將在第一次開啟資料庫連線前初始化OpenSSL庫。 當do_crypto是非零時,libcrypto庫將被初始化。 預設情況下(如果沒有呼叫PQinitOpenSSL),兩個庫都會被初始化。 當 SSL 支援沒有被編譯時,這個函式也存在但是什麼也不做。

如果你的應用使用並且初始化OpenSSL或者它的底層libcrypto庫, 你必須在第一次開啟資料庫連線前以合適的非零引數呼叫這個函式。 同時要確保在開啟一個資料庫連線前已經完成了初始化。

PQinitSSL

允許應用選擇要初始化哪個安全庫。

void PQinitSSL(int do_ssl);

這個函式等效於PQinitOpenSSL(do_ssl, do_ssl)。 這對於要麼初始化OpenSSL以及libcrypto 要麼都不初始化的應用足夠用了。

PQinitSSLPostgreSQL 8.0 就存在了, 而PQinitOpenSSL直到PostgreSQL 8.4 才被加入, 因此PQinitSSL可能對那些需要與舊版本 libpq一起工作的應用來說更合適。

本文轉自PostgreSQL中文社群,原文連結:33.18. SSL 支援


相關文章