TCP-Wrapper
TCP wrappers 通常被稱爲 wrappers,它是由 Wieste Venema 編寫,已經出現幾年了。其背後的思想很簡單,其要旨是可以在 (UNIX/Linux) 主機上快速輕鬆地鎖定流行的通過 TCP 訪問的客戶端。
Wrappers 允許系統管理員控制 wrappers 支持的基於 TCP 的服務或守護進程的訪問。Tcpd 控制從 /etc/inetd.conf 中運行的 TCP 守護進程。不過,很多基於 TCP 的應用程序已加入 wrappers 支持(一般使用 libwrap 庫),並且能感知 wrapper;不通過 /etc/inetd.conf 進行控制也沒有關係。可以在 wrappers 下進行訪問控制的通常有 telnet、ssh、sendmail、ftp 包、pop3 和 stunnel。
Wrappers 提供對基於 UDP 的連接的有限控制,不過我建議使用內置或第三方防火牆進行基於 UDP 的訪問。
如果要看應用程序是否支持 wrapper,使用 strings 命令和 grep 獲取 hosts_access 或 host:
# strings /usr/sbin/sshd|grep hosts_access``@(#)65 1.1 src/tcpwrapper/usr/sbin/tcpwrapper/hosts_access.c, tcpwrap, 53twrp2``10, 0617A_53twrp210 2/27/06 04:52:25
或者可以使用 ldd 命令:
ldd </``path``/application> | grep libwrap
wrappers 守護進程稱爲 tcpd。得到調用的是它,而非 /etc/inetd.conf 文件中的實際守護進程。Tcpd 讀取兩個文件,hosts.allow 和 hosts.deny,讀取時基於這兩個文件中的規則。當找到第一條規則匹配後,會拒絕或允許調用客戶端的訪問。所有操作都會被記錄到消息文件或指定的日誌文件中,這可以通過 syslog 來確定。通常情況下,hosts.allow 包含允許訪問的規則,而 hosts.deny 包含拒絕訪問的規則。
下面看一下典型的 telnet 客戶端場景,它是這樣工作的。客戶端試圖通過 telnet 會話連接到配置有 wrappers 的主機上。未知的客戶端連接到 wrappers 守護進程,而不是實際的 telnentd 守護進程。根據 hosts.allow 或 hosts.deny 文件中的規則,會允許或拒絕該客戶端的訪問。如果拒絕訪問,就會終止 telnet 連接。如果該客戶端符合允許訪問規則,那麼 tcpd 就會交出對所調用的實際守護進程的控制權(本例中是 telnetd)。無論哪種情況,許可或拒絕訪問都會通過 syslog 被記錄下來。
構建 wrappers
…
配置 wrappers
下一個任務是在 /etc/inetd.conf 中調用 tcpd 而不是實際的守護進程或服務。首先,創建 /etc/inetd.conf 的備份。在本例中,我僅僅替換想要控制訪問的守護進程。我會用 tcpd 替代 ftpd 和 telnetd 作爲 /etc/inetd.conf 中的調用守護進程。隨意保護此文件中的其他守護進程。/etc/inetd.conf 中我們感興趣的行有:
ftp stream tcp6 nowait root /usr/sbin/ftpd ftpd ``telnet stream tcp6 nowait root /usr/sbin/telnetd telnetd -a
我們只是替換想要保護的守護進程,本例中是用 tcpd 替換 ftpd 和 telnetd。編輯完成後,更改以下配置:
ftp stream tcp6 nowait root /usr/sbin//tcpd ftpd``telnet stream tcp6 nowait root /usr/sbin/tcpd telnetd -a
下一步,刷新 inted 讓更改生效。
# refresh -s inetd
根據以上所述,對於其他的 wrapper 支持的第三方應用程序,應查詢 hosts.allow 和 hosts.deny 文件。履行文件中的規則從而拒絕或允許對自己的客戶端的訪問是應用程序的責任。我們現在開始配置主機文件。
wrappers 會默認記錄到 /var/adm/messages,使用的是設備級的權限:
auth.info /var/adm/messages
如果您在 makefile 中指定了 LOCAL 設備,那麼您必須告訴 syslog 使用 syslog.conf 中哪個文件。以下示例中,所有在 wrappers 中使用 LOCAL 的消息都記錄到 /var/adm/wrappers.log 文件中。
local0.info /var/adm/wrappers.log
確保在重啓 syslog 之前創建 wrappers.log 文件:
# refresh -s syslogd
規則
要關閉 wrappers,只需將 hosts.allow 和 hosts.deny 文件改成其他文件名即可。如果不存在允許或拒絕訪問文件,wrappers 將不會使用訪問控制,從而有效關閉 wrappers 。或者將主機文件清空或清零,這會有同樣的效果。
Wrappers 首先在 hosts.allow 文件中查找規則匹配。如果找到匹配,那麼 tcpd 會根據規則停下來,批准或拒絕訪問。如果在 hosts.allow 文件中未找到匹配,那麼 tcpd 會讀取 hosts.deny 文件直到找到匹配。如果找到匹配,就拒絕訪問,否則批准訪問。
我在前面提到了兩個文件 hosts.allow 和 deny,但根據規則的靈活性,可以只用一個文件,通常是 hosts.allow 來包含 wrappers 所有規則。
Wrappers 會查詢 hosts.allow 和 hosts.deny 中的規則來確定訪問。規則的基本格式是:
daemon, daemon, ...: client, client, ...: option
其中:
daemon | 要監控的服務,如 telnetd、ftpd、sshd |
---|---|
client | 主機名、IP 地址/IP 範圍,或域名 |
選項有:
allow | 對客戶端的訪問 |
---|---|
deny | 對客戶端的訪問 |
except | 會匹配第一個列表中所有項,除非匹配第二個列表。例如,允許 domainA 中所有項,除了 hostX.domainA 和 hostY.domanA。 |
當一行有多個守護進程或客戶端時,用逗號分隔開來。可以用 ALL 關鍵字來表示所有守護進程或所有客戶端。
LOCAL 關鍵字表示匹配所有不包含點號(“.”)的主機;這表示所有與域不相關的主機。
如果規則允許的話,在每個規則末尾都加上允許或拒絕選項,這是一個好的做法、好的習慣(因爲這可以清晰地描繪訪問規則,尤其是在 hosts.allow 中有多個允許或拒絕規則時)。
還有一些其他的選項,我將在稍後演示。現在,我們將訪問控制結合在一起。
對 hosts.allow 和 hosts.deny 的更改是動態的。一旦文件保存,更改就會生效。
一個好的起點是,僅僅允許您想要訪問主機的客戶端使用允許的守護進程,拒絕其他所有客戶端。
所以,hosts.deny 可以使用以下規則拒絕所有客戶端訪問所有守護進程:
ALL:ALL
本節的其他示例都是隻與 hosts.allow 文件有關。爲了能讓所有守護進程從本地主機(即,與域名不相關的主機)訪問,可以使用:
ALL:LOCAL : allow
就我個人而言,我不喜歡使用在任何主機上匹配的 LOCAL 模式,因爲網絡中所有主機應該屬於您的或是某個域。如果原來不是,那麼應該是的。儘管如此,在一些小型網絡的情況下,卻不是這樣,LOCAL 允許這些主機訪問。
我們假設僅僅允許屬於 mydomain.com 域的主機使用 telnet 或 ssh。以下的 hosts.allow 條目能完成此任務:
telnetd,sshd:.mydomain.com :allow
請注意本例中 mydomain.com 之前的點號(“.”)。這是個通配符,表示所有主機以 mydomain.com 結尾。我們還在規則結尾指定這是一條允許規則。儘管這不是嚴格限制,但如前所述,這樣做是一種好的做法。
現在進一步假設我們允許使用以下 IP 地址遠程登錄 ssh 和 telnet:192.168.4.10 和所有以 192.168.6 開頭的 IP 地址。請再次注意,在部分 IP 地址後使用點號;這相當於 192.168.6.*.,或者更精確一點,以 192.168.6 開頭的所有 IP 地址。另一種看待 192.168.6. 範圍內 IP 地址的方法是等於 192.168.6/24 或所有 192.168.6.1 與 192.168.6.254 之間的 IP 地址。
另外,我們還想允許使用 telnet 和 ssh 訪問以下域:mydomain.com 和 mydomain2.com 域。以下命令能完成此任務:
telnetd,sshd:.mydomain.com, .mydomain2.com :allow``telnetd,sshd:192.168.4.10 , 192.168.6.: allow
現在,我們假設允許從 mydomain.com 域中的所有主機上進行 ftp 訪問,除了 mydomain.com 中的兩個主機:uktrip1 和 uktrip2 。通過使用允許規則,我們可以利用 except 選項提供兩個列表,讓 “except” 左側的主機允許訪問,“except” 右側列表中包含的主機拒絕訪問。
telnetd,sshd:.mydomain.com :allow``telnetd,sshd:192.168.4.10 , 192.168.6.: allow``ftpd:.mydomain.com except uktrip1.mydomain.com, uktrip2.mydomain.com : allow
我們現在看看拒絕規則。要拒絕 192.168.8. 和 192.168.9. 的 telnet 訪問,但允許 192.168.6. 的 telnet 訪問,我可以使用:
telnetd :192.168.8., 192.168.9.: deny``telnetd :192.168.6.: allow
前一個示例也可以用 except 選項來改寫:
telnetd:192.168.6. except 192.168.8., 192.168.9.: allow
Wrappers 會將消息記錄到 /var/adm/messages 文件中。消息文件中一個典型的名爲 tardis 的被拒絕 telnent 連接會像這樣:
Oct 23 15:50:55 rs6000 auth|security|warning telnetd[270546]: refused connect from`` ``tardis
一個典型的名爲 tardis 的失敗的 ssh 連接像這樣:
Oct 23 15:53:36 rs6000 auth|security:info sshd[262252]: refused connect from tardis
如果打開 PARANOID,那麼 wrappers 會通知您所有無法解析的主機與 IP 不匹配情況:
error ftpd[2605110]: warning:/etc/hosts.allow, line 2: host name/address mismatch: ``192.168.7.12 != uktrn004.mydomain.com
有時候能看到哪些主機 DNS 條目不正確也是好事,這樣可以被負責 DNS 維護的人員糾正過來。在公司內部網絡尤其如此。與拒絕不匹配主機/IP 不同的是,只允許域用戶進入(假設這是在安全的公司網絡中)。在以下示例中,所有屬於 mydomain.com 域的用戶都允許訪問,請注意對所有守護進程都使用了 ALL:
ALL:PARANOID, mydomain:allow
PAM
對於 Linux 用戶,安全地共享文件是一項麻煩的任務。例如,需要費力地回想多個密碼,並且重新設計系統訪問應用程序(如 login、su、password、ftp 等)十分耗費時間。增加這一複雜度的是驗證 過程,在該過程中,系統將識別用戶併爲該用戶提供相應的訪問控制。
PAM 的使用歷史記錄
PAM 是關注如何爲服務驗證用戶的 API。在使用 PAM 之前,諸如 login(和 rlogin、telnet、rsh)之類的應用程序在 /etc/passwd
中查找用戶名,然後將兩者相比較並驗證用戶輸入的名稱。所有應用程序使用了這些共享服務,但是並未共享實現細節和配置這些服務的權限。
接下來,應用程序開發人員嘗試編寫自定義過程代碼。在此過程中,需要分離應用程序與安全模塊(通用安全模塊可以在應用程序之間共享並且可以根據需求進行配置)。
PAM 機制將把多個低級別驗證模式集成到高級別 API 中,該 API 將允許以獨立於底層驗證模式的方式編寫使用驗證的程序。PAM 的主要特徵表現爲通過 /etc/pam.d
或 /etc/pam.conf
文件實現動態驗證配置。
PAM 可以被配置爲拒絕某些程序對用戶進行驗證,或者在某些程序嘗試驗證時發出警告。PAM 程序將使用 PAM 模塊(驗證模塊):這些模塊在運行時與應用程序綁定在一起才能工作。
圖 1 顯示了 PAM 模塊的基本流程。
圖 1. PAM 庫將解析配置文件並將模塊裝入其中
哪些操作系統支持 PAM?
PAM 最初是由 Sun Microsystems 於 1995 年開發的,並且以下操作系統版本(及更高版本)都提供支持:
- RedHat 5.0
- SUSE 6.2
- Debian 2.2
- Mandrake 5.2
- Caldera 1.3
- TurboLinux 3.6
最新版本的 Solaris™、AIX®、HP-UX 和 Mac OS® X 也支持 PAM。PAM 後來被標準化爲 X/Open UNIX® 標準化流程(在 X/Open 單點登錄服務(XSSO)架構中)的一部分。
PAM 模塊是什麼樣子的?
安裝 PAM 是一個逐步的過程。要獲得安裝說明,請參閱 參考資料。
PAM 模塊是按模塊類型歸類的。任何給定的模塊至少要實現四種模塊類型功能之一:
- 驗證模塊用於驗證用戶或設置/銷燬憑證。
- 帳戶管理模塊將執行與訪問、帳戶及憑證有效期、密碼限制/規則等有關的操作。
- 會話管理模塊用於初始化和終止會話。
- 密碼管理模塊將執行與密碼更改/更新有關的操作。
PAM 將提供不同的功能,例如單點登錄驗證、訪問控制等。每個功能的實現都是由不同的模塊處理的。下面是一些主要模塊:
pam_access
將使用登錄名/域名,根據 /etc/security/access.conf 中的預定義規則交付日誌守護進程樣式的登錄訪問控制。pam_cracklib
將根據密碼規則檢查密碼。pam_env sets/unsets
環境變量來自 /etc/security/pam_env_conf。pam_debug
將調試 PAM。pam_deny
將拒絕 PAM 模塊。pam_echo
將打印消息。pam_exec
將執行外部命令。pam_ftp
是匿名訪問模塊。pam_localuser
要求將用戶列於 /etc/passwd 中。pam_unix
將通過/etc/passwd
提供傳統密碼驗證。
還有許多其他模塊(pam_userdb
、pam_warn
、pam_xauth
),這些模塊將獲取返回的一組值(這些模塊的詳細信息可以在 參考資料 的 PAM 管理指南中找到)。
配置 PAM
PAM 配置通常是在 /etc/pam.d
或 /etc/pam.conf
(用於舊版本)中的配置文件中實現的。
配置文件的結構
對於使用 PAM 的各項服務,目錄中都有一個對應的文件,其中包含應當如何獲取該服務的驗證及帳戶信息的規則或說明。通常每一行有一個規則。
PAM 配置文件中的字段包括:
Service_name
將指定服務/應用程序的名稱(默認值爲 OTHER)。Module_type
將爲Service_name
字段中的相應服務指定模塊類型(auth/account/session/passwd
)。Control_flag
將指定模塊的堆棧行爲。它可以獲取諸如requisite
、required
、sufficient
和optional
之類的值。Module_path
將指定實現模塊的庫對象的路徑名稱。默認情況下,它將被設爲/lib/security
。Module_options
/module_args
(可選字段)將指定可以傳遞給服務模塊的選項或實參。
模塊將按照在配置文件中列出的順序被調用,這取決於每個條目允許的 Control_flag
的值。Control_flag 值包括:
- Required:堆棧中的所有 Required 模塊必須看作一個成功的結果。如果一個或多個 Required 模塊失敗,則實現堆棧中的所有 Required 模塊,但是將返回第一個錯誤。
- Sufficient:如果標記爲 sufficient 的模塊成功並且先前沒有 Required 或 sufficient 模塊失敗,則忽略堆棧中的所有其餘模塊並返回成功。
- Optional:如果堆棧中沒有一個模塊是 required 並且沒有任何一個 sufficient 模塊成功,則服務/應用程序至少要有一個 optional 模塊成功。
PAM 配置文件示例
表 1 顯示了各種操作系統中的 PAM 配置文件的一些示例。
表 1. PAM 配置文件的世界
系統 | 配置文件所在位置 | 類型 | Control_flag | 模塊 |
---|---|---|---|---|
Red Hat | /etc/pam.d | auth | required | /lib/security/pam_unix.so |
Red Hat | /etc/pam.d | account | sufficient | /lib/security/pam_unix.so |
Red Hat | /etc/pam.d | session | required | /lib/security/pam_limit.so |
AIX | /etc/pam.conf | auth | required | /usr/lib/security/pam_aix |
AIX | /etc/pam.conf | account | required | /usr/lib/security/pam_aix |
AIX | /etc/pam.conf | password | required | /usr/lib/security/pam_aix |
zSUSE 64-bit | 32-bit | /etc/pam.conf | auth | required | /lib64/security/pam_unix.so | /lib/security/pam_unix.so |
zSUSE 64-bit | 32-bit | /etc/pam.conf | account | required | /lib64/security/pam_unix.so | /lib/security/pam_unix.so |
zSUSE 64-bit | 32-bit | /etc/pam.conf | session | required | /lib64/security/pam_unix.so | /lib/security/pam_unix.so |
Solaris | /etc/pam.conf | auth | required | /usr/lib/security/pam_unix.so.1 |
Solaris | /etc/pam.conf | account | required | /usr/lib/security/pam_unix.so.1 |
Solaris | /etc/pam.conf | password | required | /usr/lib/security/pam_unix.so.1 |
HP-UX | /etc/pam.conf | auth | required | libpam_unix.so.1 |
HP-UX | /etc/pam.conf | account | required | libpam_unix.so.1 |
HP-UX | /etc/pam.conf | password | required | libpam_unix.so.1 |
PAM 的 “other” 文件
默認的 PAM 配置文件 /etc/pam.d
用於沒有明確配置的所有其他服務,並且可能是 PAM 所依賴的最簡單而又最健壯的默認文件。該文件內部類似如下所示:
/etc/pam.d/other File
auth required pam_warn.so
auth required pam_deny.so
account required pam_warn.so
account required pam_deny.so
password required pam_warn.so
password required pam_deny.so
session required pam_warn.so
session required pam_deny.so
此文件非常簡單。對於所有模塊類型,Control_flag 都是一樣的:required
。調用兩個模塊:
- 首先,調用
pam_warn.so
來記錄關於正在進行的嘗試的信息。 - 然後調用
pam_deny.so
僅返回錯誤並防止發生任何類型的連接或驗證。
因此,使用 PAM 的所有服務都必須被明確配置爲允許驗證;否則,嘗試將失敗。
設計簡單 PAM 登錄應用程序的 10 個步驟
這 10 個步驟可以幫助您實現自己的 PAM 應用程序並幫助您瞭解 PAM 會話的工作方式:
- 包括 PAM 實現的頭文件(例如,pam_appl.h、pam_misc.h)。
- 在
main
函數中,使用惟一的句柄初始化 PAM 庫 libpam.so(該庫將裝入應用程序的配置文件中指定的模塊)。 - 嘗試驗證所有模塊並處理失敗場景。
- 檢查用戶憑證和帳戶詳細信息。
- 打開一個新 PAM 會話。
- 爲使用憑證的用戶設置環境。
- 當用戶完成時,取消用戶環境。
- 關閉 PAM 會話。
- 從帶有句柄值的 libpam.so 庫中退出。
- 退出。