[FrontPage] [TitleIndex] [WordIndex

This is a read-only archived version of wiki.centos.org

Postfix 規限

<<TableOfContents: execution failed [Argument "maxdepth" must be an integer value, not "[1]"] (see also the log)>>

敬請注意:

/!\ 注意:本文檔是為 CentOS 5 而撰寫的。它的內容對 CentOS 6 或較後版本也許並不準確。

1. 引言

假如你遵從基本的 postfix 指南,你便能建立一台簡單的 postfix 郵件伺服器發放及接收電郵。不過,你多數已經發現這台 postfix 郵件伺服器會接收所有電郵,連同垃圾郵件也亳無保留地接受。據估計,互聯網上發放的所有電郵當中,超過 80% 的電郵是垃圾郵件,又名為「未經同意的大量電郵(UBE)」或「未經同意的大量電郵(UCE)」,因此它們對任何一位郵件管理員來說都是個重大的挑戰。本指南將會以獨立單元的方式檢視 postfix 所提供、用來對付垃圾郵件的一些規限,讓讀者能夠在基本的 postfix 指南之上按喜好來加插它們。

2. Postfix 與垃圾郵件

互聯網主要建基在信任這個原則之上,而 UBE 正是濫用這份信任來發放大量的垃圾郵件。當我們把任何形式的規限加諸在電郵時,我們便偏離了信任的原則,也會冒著規限或阻塞合法電郵的風險。故此我們所實施的規限必須保守,並且要徹底地測試及監視它們。你的用戶會感激你限制垃圾郵件的數量,但他們不會因為阻塞了合法的電郵來多謝你。

我們會利用 3 種 postfix 規限類別來檢視連線到郵件伺服器的客戶端所提供的資訊:

慶幸地,很多垃圾郵件發放者懶得嚴格地遵從 RFC 指引,所以我們能夠透過以上的規限類別來辨認顯而易見的垃圾郵件,並且在它們進入郵件伺服器前拒絕它們。在垃圾郵件進入伺服器前拒絕它們不但能夠減省頻寬,更可以減除郵件伺服器進一步處理它們所須的資源。

規限的運作方式是透過處理一堆規則來決定 postfix 對每封郵件所要採取的行動。可能的結果包括 OK(沒有問題)、REJECT(拒絕)或 DUNNO(不知道)。規限是按它們的排列次序來運算的。只要有一條規則傳回 REJECT,該郵件便會立即被拒絕和不再被處理。假若有一條規則傳回 OK,同類的規則便不會再被運算,而下一組的規則會開始被運算,直至該郵件成功地通過全部規則類別或被其其中一條規則所拒絕。所有,舉個例說,某郵件可能從 smtpd_sender_restriction 取得 OK,但依然可以被其後的 smtpd_recipient_restriction 規則所拒絕。因此,我們須要給予我們的規限規則詳細考慮。如果一個郵件並未被任何規則所拒絕,預設的政策是接納該郵件。

要更清楚理解各種規限類別及它們如何被運用,讓我們 telnet 進入我們的郵件伺服器和寄一封電郵給自己,並更深入地檢視 smtp 的運作:

telnet 192.168.0.2 25                           # Comments
Trying 192.168.0.2...
Connected to 192.168.0.2 (192.168.0.2).
Escape character is '^]'.
220 mail.example.com ESMTP Postfix              # <-smtp_client_restrictions
HELO mail.example.com                           # <-smtp_helo_restrictions
250 mail.example.com                            #
MAIL FROM:<ned@example.com>                     # <-smtp_sender_restrictions
250 2.1.0 Ok                                    #
RCPT TO:<ned@example.com>                       # <-smtp_recipient_restrictions
250 2.1.5 Ok                                    #
DATA                                            # <-smtp_data_restrictions
354 End data with <CR><LF>.<CR><LF>             #
To:<ned@example.com>                            # <-header_checks
From:<ned@example.com>                          #
Subject:SMTP Test                               #
This is a test message                          # <-body_checks
.                                               #
250 2.0.0 Ok: queued as 301AE20034
QUIT
221 2.0.0 Bye
Connection closed by foreign host.

smtpd 的 helo、sender 及 recipient 規限的主要優點就是它們在電郵的內文被發放/接收之先已經可以被運算,因此潛在的垃圾郵件可以在 smtp 進程的早段被拒絕,而不必佔用額外頻寬及/或處理器的資源。讓我們一起看某些規限的實例來明白它們的用途。所有規限都被加進 /etc/postfix/main.cf 這個 postfix 主設定檔。

3. 客端身份規限

當一台客端系統連線到我們的郵件伺服器時,它必須利用 HELO 指令來辨明身份。很多垃圾電郵發放者會嘗試跳過這一步、傳送不合理的錯誤資料、或者刻意地混淆身份來奪得存取權。無論如何,我們可以安全地拒絕那些設置上有嚴重錯誤或刻意地混淆身份的客戶端。

# /etc/postfix/main.cf
# HELO 規限:
smtpd_delay_reject = yes
smtpd_helo_required = yes
smtpd_helo_restrictions =
    permit_mynetworks,
    reject_non_fqdn_helo_hostname,
    reject_invalid_helo_hostname,
    permit

註: Postfix 2.2(CentOS 4)分別採用 reject_non_fqdn_hostname 及 reject_invalid_hostname。

第一行(smtpd_delay_reject)容許 smtp 繼續進行對話直至接收內文時才拒絕它,這個用意是要讓我們能記錄完整的寄件者及收件者資料。這亦是採用 helo_restrictions 的一個先決條件。第二行(smtpd_helo_required)拒絕來自無法辨明身份的系統的郵件。

我們的 smtpd_helo_restrictions 在第三行開始。permit_mynetworks 告訴 postfix 接納來自獲信任、定義在 mynetworks 中的機器,這樣來自我們信任的客戶端的電郵便不須再通過其它 helo 規限的檢查。如果 HELO 指令所提供的主機名稱並非如 RFC 指引所要求的完整域名,reject_non_fqdn_helo_hostname 將會拒絕那些連線。拒絕那些不願正確地辨認自己的客戶端的連線請求是絕對安全的。同樣道理,要是 HELO 的主機名稱語法不正確,reject_invalid_helo_hostname 將會拒絕那些連線請求。最後我們容許郵件接受進一步的過濾。

還有一個不時會採用的進階選項就是 reject_unknown_helo_hostname,它拒絕的郵件就是那些無法以 helo 指令提供擁有 DNS A 或 MX 記錄的主機名稱。然而這個設定必須小心使用,因為它會拒絕那些來自合法、但暫時遇上 DNS 問題的系統的郵件,導致誤報出現。

4. 寄件者規限

下一步就是透過寄件者規限來過濾不合法的寄件者:

# /etc/postfix/main.cf
# 寄件者規限:
smtpd_sender_restrictions =
    permit_mynetworks,
    reject_non_fqdn_sender,
    reject_unknown_sender_domain,
    permit

同樣地,我們首先容許來自我們的網絡的寄件者(permit_mynetworks)。接下來的兩行拒絕那些寄件者電郵地址不整全或不存在的郵件,因為沒有實在理由要接納他們的郵件。reject_non_fqdn_sender 會按 RFC 的要求拒絕那些 MAIL FROM 地址並非完整域名的電郵。reject_unknown_sender_domain 會拒絕那些沒有 DNS A 或 MX 記錄的 MAIL FROM 地址,與及擁有異常 MX 記錄的地址,例如記錄內含有零長度的 MX 主機名稱。reject_unknown_sender_domain 的回覆碼是 450(稍後再試),用來應付暫時性的 DNS 問題。此外,由於 MAIL FROM 是退回郵件的地址,接收來自不明網域的郵件是不合情理的。最尾一行容許郵件接受下階段的過濾。

5. 收件者規限

到此刻,我們可以確定客端機器並非胡亂設置,而寄件者至少有機會是合法的。最後的步驟就是檢視客戶端是否有權限發放到指定的收件者,並且套用一些外置、非 postfix 的檢查在所剩無幾、能達至這個步驟的郵件。

# /etc/postfix/main.cf
# 收件者規限:
smtpd_recipient_restrictions =
   reject_unauth_pipelining,
   reject_non_fqdn_recipient,
   reject_unknown_recipient_domain,
   permit_mynetworks,
   reject_unauth_destination,
   check_sender_access
         hash:/etc/postfix/sender_access,
   reject_rbl_client zen.spamhaus.org,
   reject_rbl_client bl.spamcop.net,
   check_policy_service unix:postgrey/socket,
   permit

postfix 支援一個名為流水線的技術,透過同時發出多個 smtp 指令來加快傳遞大量的電郵。這個協議要求客戶端先檢查伺服器是否支援流水線。很多垃圾郵件的寄件者為要儘快發送他們的郵件,會不等候批准便發出一連串的指令。reject_unauth_pipelining 阻止那些進行大量郵寄的軟件濫用流水線來加快發送電郵。

接下來的數行應該有點面善,用來拒絕送往不存在或不可能存在網域的郵件。首先我們按 RFC 的要求拒絕那些 RCPT TO 地址不是完整域名的郵件(reject_non_fqdn_recipient),然後假如我們郵件伺服器並非收件者的終極目的地、RCPT TO 地址沒有 DNS A 或 MX 記錄、又或者 MX 記錄異常,郵件都會被拒絕。reject_unknown_recipient_domain 的回覆碼是 450(稍後再試),用來應付暫時性的 DNS 問題。同樣地,permit_mynetworks 告訴 postfix 接納我們網絡上的本地用戶連線。

接著那行,reject_unauth_destination,是極之重要的,因為它告訴 postfix 假如郵件的收件網域並非由本地管理,而我們又不是該網域的後備伺服器,但不要接納這些郵件。沒有這一行,我們的伺服器便會成為一個公開的轉發站。

下一個設定,check_sender_access,讓我們可以利用 MAIL FROM 欄的完整或部份電郵地址及網域來實踐白名單及黑名單,通過對照一個存取列表來傳回 OK 或 REJECT 值。首先我們必須建立這個對照表,在本範例中它是 /etc/postfix/sender_access 這個純文字檔:

# /etc/postfix/sender_access
#
# 配對 MAIL FROM 欄內的寄件者用的黑/白名單。範例……
#
myfriend@example.com    OK
junk@spam.com           REJECT
marketing@              REJECT
theboss@                OK
deals.marketing.com     REJECT
somedomain.com          OK

我們從上面範例會看見郵件可以根據 MAIL FROM 欄內的完整電郵地止、任何網域的用戶名稱、網域或局部網域來放進黑名單或白名單。請留意這些都只是例子,而普遍來說你不應該將自己的網域放進白名單內,因為垃圾郵件寄件者多數會把寄件人地址改為你的網域。建立了 sender_access 檔後,你必須執行 postmap 這個指令在它之上來建立一個供 postfix 採用的索引版本(你也須在每次更改該檔案後重複這步驟):

postmap /etc/postfix/sender_access

這是我們的最後一個 postfix 內置檢查。餘下來的檢查會查詢外置來源或工具程式。

接著我們會進行一些實時的黑名單(RBL)檢查。RBL,又名為 DNS 黑名單(DNSBL),是一個由第三方提供 IP 地址列表的服務,而這些 IP 正進行某類型非法活動,例如:發放垃圾郵件或病毒等不良內容。reject_rbl_client 這行會導致 postfix 利用所列舉的資料庫進行檢查,並拒絕那些來不良源頭的電郵。由於這些檢查涉及一個 DNS 對照,論資源它們是相對地「昂貴」,因此最好把它們放在檢查的結尾,透過事先去除多數的垃圾郵件來減低它們發生的次數。同樣地,我們順理成章地把先列舉最有效的資料庫,旨在減省拒絕一封(垃圾)郵件所需的對照次數。

網上有很多 DNSBL,你選用的數量及供應者亦適隨尊便,但你應該定時檢視你的日誌來複核它們的効率(提示:安裝 postfix-pflogsumm 這個套件並使用 pflogsumm 這個指令來分析你的 postfix 日誌)。請留意採用 DNSBL 會引入誤報的可能性,因為我們依賴列表維護者加入不法地址的政策。有些効率十分高、有些做不了甚麼、有些拒絕合法郵件的數量與垃圾郵件同樣多。讀者可參詳 http://stats.dnsbl.com/ 取得更多資料及各 DNSBL 的即時數據。

最後一個檢查,check_policy_service,是用來執行一個附加的應用程式或腳本,這個例子採用了連結到 unix 通訊端的 postgrey。postgrey 可以高效率地清除垃圾郵件,而且有份獨立的指南專門關於 postgrey 在 postfix 郵件伺服器上的安裝。我們極力鼓勵讀者接著便閱讀該指南。

6. 總結

在這份指南裡我們看見如何用 postfix 的規限來拒絕電郵來自明顯設置上錯誤的客戶端,及那些沒理由發放電郵到我們伺服器的人。我們刻意地實施保守的規限,目的為要防止誤報及確保能在任何 postfix 安裝下應用。postfix 的規限,尤其是拒絕沒有完整域名的 helo 主機名稱,能攔截多達 30% 的垃圾郵件,而利用 1 至 2 個優良的 DNSBL 能攔截剩餘的垃圾郵件的 90% 或以上。再配合 greylisting 能過濾技術,理論上絕大部份(~99%)的垃圾郵件都可以在進入郵件伺服器之先被過濾掉,從而節省頻寬及處理的資源。這份指南旨在補充基本的 postfix 指南

7. 鳴謝

本篇文章的靈感及內容源自 Kirk Strauser 在 http://www.freesoftwaremagazine.com/articles/focus_spam_postfix 以「相同方式共享 2.5 通用版」刊登的傑出指南

……

Translation of revision 29


2023-09-11 07:23