第十四章 郵件伺服器安裝

郵件伺服器是網際網路上常用的伺服器,我們平常收發電子郵件都必須經過郵件伺服器。通常一般人都是使用 ISP 或免費的電子郵件信箱, 由於這種服務的使用者很多,您的電子郵件帳號通常很長,而且不是您所喜歡的名稱。例如 ,如果您的名字是 Alex, 您大概很難申請到 alex@gmail.com 這麼好記的位址,只能申請到類似 alex20200410_tw@gmail.com 這種又臭又長的信箱。 如果您想要有比較好的信箱位址,則必須自行架設一台郵件伺服器。

本章將介紹如何使用 FreeBSD 架設郵件伺服器,讀完本章後,您將可以對郵件伺服器的運作更加了解。本章將包含下列主題:

14.1 電子郵件概論

一個電子郵件位址可以分為二個部份,第一個部份是使用者名稱,第二個部份是主機名稱。以 john@yahoo.com 為例, yahoo.com 就是主機名稱,而 john 為使用者名稱。john@yahoo.com 可以念作「John at yahoo.com」, 翻成中文就是在 yahoo.com 上的使用者 John。

假設 Alex 使用的信箱是 alex@gmail.com,則當 Alex 要寄信給 john@yahoo.com 時,會經過下列步驟:

  1. 首先 Alex 從個人電腦中寫好一封信,送到他所屬的 gmail.com 的主機中。
  2. gmail.com 會先將信件存在自己的機器上的暫存區。
  3. gmail.com 會檢查信件目的地,並查找 yahoo.com 的 IP 位址。
  4. 接著經由網際網路將信件送到 yahoo.com 的主機。
  5. yahoo.com 的主機收到信後,發現是給自己機器中的使用者,所以將信件存放到使用者的新件匣中。
  6. 當 John 有空時,從家裡打開電腦,並主動去 yahoo.com 檢查是否有新的信件,當發現有新的信,則下載到自己的電腦中。

圖 14-1

如果 alex@gmail.com 要寄信給 john@gmail.com,因為寄信者和收信者使用同一個郵件伺服器,所以在上述步驟二中, gmail.com 的主機發現收信者是自己機器的使用者,則會將該信件存放在使用者的新件匣中。

從寄信到收信的流程中,每一個網路上的元件都扮演著不同的角色,我們分別來談一下每一個角色的功能:

圖 14-2

當我們在寄信時,所使用的是 SMTP (Simple Mail Transfer Protocol) 通訊協定,在一台郵件伺服器上,必須要先安裝郵件伺服器軟體,以接收 SMTP 協定所寄來的信件。 MTA 和 MTA 之間傳送信件時也是使用 SMTP 協定。而收信時,使用的是 POP3 (Post Office Protocol) 或是 IMAP (Internet Message Access Protocol) 協定。

一般常用的 SMTP 軟體為 FreeBSD 內附的 Sendmail、Exim、或 Postfix。而收信時所使用的 POP3 及 IMAP 軟體 FreeBSD 並未內建, 因此我們必須自行安裝。然而做為一台 Mail Server,我們要設定的是最少要做到可以正常使用 POP3/IMAP 及 SMTP 來讓使用者收發信。 另外,我們也將介紹使用 Web 介面的郵件收發軟體,Web 介面的郵件收發軟體可以讓使用者不必使用 Outlook 等軟體即可經由任何作業系統的瀏覽器輕鬆收發信件。

傳統上,SMTP 在接受使用者寄信時,並不須經過身份認証,任何人都可以使用你的主機來製造垃圾信。 因此 FreeBSD 內建的 Sendmail 是不接受 SMTP 寄信的。而一般的 ISP 業者大多是以控制連線來源的方式, 禁止非允許網域的使用者 RELAY。但如果我們以控制連線來源的方式,便無法在其他非允許的IP位址使用 SMTP, 這對於想要任何地方都可以發信的人十分不分便。因此,本章裡我們將介紹如何讓使用者透過 FreeBSD 使用 SMTP 身份認證的功能來寄信, 讓要使用諸如 Outlook 以 SMTP 寄信的使用者必須先通過本機的身份認證。

在開始架設郵件伺服器之前,您必須先設定好 DNS。由於傳送信件時,必須查找目的地主機的 IP。如果您的主機沒有合法的 DNS 設定, 信件將無法正確送達。假設您要架設一台處理 twbsd.org 的郵件伺服器,在 DNS 設定方面有二種方式。 第一種是直接將您的主機名稱設為 twbsd.org,並設定 DNS 將 twbsd.org 對映到您的主機 IP。第一種方法是使用 DNS 的 MX 設定, 將 twbsd.org 的郵件交由另一台主機處理。如果您的 DNS 是交由申請單位代管,則只要到申請單位設定好名稱對映即可。 如果您要自行架設 DNS 伺服器,請參考「DNS 伺服器」一章的說明。

另外,您的伺服器 IP 也必須設好反解,IP 名稱必須和您的主機名稱對映,如果反解不正常,有的伺服器可能會拒收您所送出的信件。

14.2 SMTP 伺服器 - Postfix

雖然目前 FreeBSD 內建的 SMTP 伺服器為 Sendmail,但很少人會使用 Sendmail。因為:

因此,我們裝使用另一套常用的郵件伺服器 ─ Postfix。Postfix 是一套由 IBM 員工於 1998 年所發展出來的 MTA 軟體, 有鑑於 Sendmail 的安全性缺點及設定複雜,Postfix 最初的目的就是為了取代 Sendmail。因此,Postfix 在使用者介面上, 有許多指令的使用方法都相容於 Sendmail。目前,Postfix 仍然十份活躍且擁有廣大的市占率。

郵件儲存在系統中的常見格式有二種:Mailbox 及 Maildir。Mailbox 是傳統格式,也是 Sendmail 所支援的格式。 它是用一個文字檔存放所有信件的內容。例如,你的信箱有 100 封信,這些信在 Mailbox 格式下,實際上是存在一個大的文字檔。 因為 Mailbox 是一個很大的文字檔,當信件多時,處理起來很慢。而且單一檔案在同時存取時常常會有 Lock 失敗的問題。

Maildir 則是一個信箱在硬碟上就是一個目錄。而每一封信都是一個檔案。 好處是每一封信件都是獨立的檔案,不要因為一個檔案損毀而失去所有信件。而且在多工存取時,效能較佳。

首先,我們使用 Ports 安裝 Postfix:

#cd /usr/ports/mail/postfix
#make install clean

接著,我們就可以編輯 Postfix 的主要設定檔 /usr/local/etc/postfix/main.cf 來設定 Postfix。 您可以直接在該檔案最後新增下列內容:

... # 設定本機名稱,如 mail.your_domain.com myhostname = mail.your_domain.com # 設定信件的網域名稱。例如,您的 email 是 alex@your_domain.com,這裡就是填入 @ 後的網域名稱。 mydomain = your_domain.com # 如果本 mail server 還要再多收其它網域的信, 例如 mycompany.co.uk、mycompany.com.tw 的信也是 # 由本伺服器處理,則可以將它加在下面: mydestination = $myhostname, localhost.$mydomain, localhost, mycompany.co.uk, mycompany.com.tw # 設定使用 Maildir 的信箱格式。 home_mailbox = Maildir/ # 啟用 SASL 認證。我們使用 Dovecot 來協助進行身份認證,因此下一章安裝 Dovecot 時,我們也會需要 # 有相對應的設定。 smtpd_sasl_type = dovecot smtpd_sasl_path = private/auth smtpd_sasl_auth_enable= yes # 啟用 SSL,並使用 Let's Encrypt 的憑證。若您未建立 SSL 憑證,請參考「網頁伺服器」一章建立 SSL 憑證。 # 以下憑證以 your_domain.com 為例,請換成您的憑證路徑。 smtpd_tls_cert_file = /usr/local/etc/letsencrypt/live/your_domain.com/fullchain.pem smtpd_tls_key_file = /usr/local/etc/letsencrypt/live/your_domain.com/privkey.pem smtpd_tls_security_level = may smtp_tls_security_level = may smtpd_tls_mandatory_protocols=!SSLv2, !SSLv3 # 設定信件大小限制,我們設定最大信件大小為 50MB mailbox_size_limit = 0 message_size_limit = 51200000 # 設定使用網路上的垃圾郵件 IP 黑名單來阻擋垃圾信。 # check_client_access 是設定黑白名單,我們可以設定某些 IP 或網域一律通過或阻擋。請 man 5 access。 # permit_mynetworks 表示允許內網使用者寄信。 # permit_sasl_authenticated 表示有通過身份認證就不需要看 IP 是不是在黑名單中。 # reject_unauth_destination 如果不是內網或通過身份認證,則不可以 Relay。 # reject_rbl_client 如果您想用使用垃圾信 IP 黑名單,可以將相對應的資料庫前的註解移除。 smtpd_client_restrictions = check_client_access hash:/usr/local/etc/postfix/access, permit_mynetworks, permit_sasl_authenticated, reject_unauth_destination, #reject_rbl_client sbl-xbl.spamhaus.org, #reject_rbl_client zen.spamhaus.org, #reject_rbl_client bl.spamcop.net, #reject_rbl_client cbl.abuseat.org, permit # 為了避免客戶端濫用,您也可以增加以下的限制 # smtpd_client_connection_rate_limit 限制同一個 client 一定時間內最多連線數量。 # 這裡指的「一定時間」由 anvil_rate_time_unit 控制,預設是 60 秒內。 # 這個值預設是沒有限制。您可以 60 秒內最多只能寄出 30 封信。 # smtpd_soft_error_limit 及 smtpd_hard_error_limit 表示當客戶端 SMTP 有錯誤時, # 如果錯誤次數超過 smtpd_soft_error_limit,則開始延遲回應 smtpd_client_connection_rate_limit。 # 例如,如果客戶端在嘗試密碼,失敗三次後,系統可以延遲回應 10 秒,如果失敗超五次 # (smtpd_hard_error_limit) 則斷線,以免客戶端繼續猜測密碼。 # smtpd_error_sleep_time smtpd_client_connection_rate_limit = 30 smtpd_error_sleep_time = 10s smtpd_soft_error_limit = 3 smtpd_hard_error_limit = 5

因為我們有設定 check_client_access,所以必須新增 /usr/local/etc/postfix/access, 並使用 postmap 去產生 Postfix 的資料庫。

#touch /usr/local/etc/postfix/access
#postmap /usr/local/etc/postfix/access

然後,請設定 /usr/local/etc/postfix/master.cf,找到下面這幾行的部份,並移除開頭的註解符號 #:

... smtp inet n - n - - smtpd -o smtpd_sasl_auth_enable=yes smtps inet n - n - - smtpd -o smtpd_tls_wrappermode=yes -o smtpd_sasl_auth_enable=yes

接下來,我們要停用系統預設的 Sendmail。請先使用下列指令停用 Sendmail。

#service sendmail stop
#sysrc sendmail_enable="NONE"

sysrc 這個指令會修改 /etc/rc.conf 的設定,並將 sendmail_enable 設為 "NONE",和直接編輯 /etc/rc.conf 的效果是一樣的。

另外,由於 Sendmail 已被停用,系統中原本會每天自動執行的一些 Sendmail 的維護工作也可以取消了。 我們可以編輯並新增 /etc/periodic.conf 加入下列內容:

daily_clean_hoststat_enable="NO" daily_status_mail_rejects_enable="NO" daily_status_include_submit_mailq="NO" daily_submit_queuerun="NO"

現在,我們就可以啟用 Postfix 了。

#sysrc postfix_enable="YES"
#service postfix start

最後,我們修改系統預設的信件程式,告訴系統預設的信件程式是 Postfix 。

#mkdir -p /usr/local/etc/mail
#install -m 0644 /usr/local/share/postfix/mailer.conf.postfix /usr/local/etc/mail/mailer.conf

這樣就完成了 Postfix 的安裝。再開始送信之前,我們還要安裝 Dovecot 才能進行身份認證並支援 IMAP 或 POP3 收信。

14.3 POP3 及 IMAP 伺服器 - Dovecot

傳統上使用 Outlook 等收信軟體時,我們會使用 POP3 來下載伺服器上的信件。在下載完畢後, 除非我們有設定在伺服器上保留原本的信件,否則預設會在下載後自動將該信件自伺服器中移除,以節省空間。

然而,如果您平常使用多台電腦,或是想在不同的地方依然可以看到之前的信件,則 POP3 就不太符合需求。 除了 POP3 外,還有一個郵件通訊協定名為 IMAP。IMAP 和 POP3 最主要的差異在於 IMAP 一開始只下載信件標題, 直到點選該信件後,它才會將信件下載至您所使用的電腦中。而在下載之後,IMAP 並不會將伺服器上的郵件刪除, 所有瀏覽過的信件依然保存於伺服器中。隨著信件越來越多,單一信箱的資料也會越來越大。 此時我們可以使用 IMAP 建立新信夾的功能,在使用者家目錄中建立許多新的資料夾,並將收件夾的信件移至新建立的資料夾中。 另外,當我們寄出新信件時,若使用 POP3 協定,則寄件備份只會存放於您寄信時所使用的電腦中, 但 IMAP 則會將寄件備份存於於伺服器中。因此,如果您常使用多台不同的電腦收信,使用 IMAP 真的很方便。

本章中,我們將介紹 dovecot,dovecot 同時支援 POP3 及 IMAP,在功能及效能上都比傳統的 IMAP 收信軟體好。

我們使用下列指令來安裝 dovecot:

#cd /usr/ports/mail/dovecot
#make install clean

當出現進階選項的視窗時,請使用預設選項即可。

安裝完後,我們要開始新增並編輯 dovecot 的設定檔 /usr/local/etc/dovecot/dovecot.conf

# 是否要允許使用沒有加密的連線。建議設成 yes 以強制使用者要進行 # 身份認證前一定要使用 SSL 加密。 disable_plaintext_auth = yes # 支援 IMAP 及 POP3 protocols = imap pop3 # 設定 SSL 憑證路徑,我們一樣使用 Let's Encrypt 的憑證, # 請將下列路徑改為您的憑證路徑。 ssl_cert = </usr/local/etc/letsencrypt/live/your_domain.com/fullchain.pem ssl_key = </usr/local/etc/letsencrypt/live/your_domain.com/privkey.pem # 設定支援的認證方式 auth_mechanisms = plain login # 設定使用 Maildir 的信箱格式。 mail_location = maildir:~/Maildir # 設定系統使用者認證方式及使用者資料庫。 passdb { driver = pam } userdb { driver = passwd } # 為了讓 Postfix 可以進行 SASL 身份認證,我們加入下列設定。 service auth { unix_listener /var/spool/postfix/private/auth { mode = 0660 user = postfix group = postfix } } # 如果您的使用者家目錄是使用 NFS 掛載,則必須加入下列設定 #lock_method = dotlock

為了讓 Dovecot 可以使用系統的 PAM 認證模組,我們必需新增 Dovecot 的 PAM 設定檔。設定檔的內容很簡單, 直接複製一份系統原本的 imap 設定檔即可:

#cp /etc/pam.d/imap /etc/pam.d/dovecot

最後,我們就可以在使用 sysrc 在 /etc/rc.conf 中啟用 Dovecot 並立即執行 Dovecot 了:

#sysrc dovecot_enable="YES"
#service dovecot start

現在我們就可以設定使用 Outlook 或 Thunderbird 來收發信。在設定 SMTP 時,請使用 Port 465,以使用 SSL/TLS 的 SMTP 連線。

14.4 網頁收信軟體 - Roundcube

很多免費信箱的使用介面都是使用瀏覽器在網頁上收發信件,例如 Gmail、Yahoo 等。在 FreeBSD 上,我們也可以安裝網頁收信軟體 - Roundcube。 Roundcube 使用 IMAP 協定來和郵件伺服器溝通,並在網頁上顯示信件。 在使用介面上,它提供了類似個人電腦上的郵件軟體介面,支援超過 80 種語言,是目前最成熟的網頁收信軟體。

Roundcube 是使用 PHP 開發的軟體,所以我們必須先架設 Apache+PHP。另外,它必須使用 MySQL 或 PostgreSQL 資料庫作後端資料儲存。 如果您還沒有設定好網頁伺服器或資料庫,請先參考網頁伺服器及資料庫系統以安裝所需伺服器。

14.4.1 安裝 Roundcube

在網頁伺服器和資料庫都安裝好之後,安裝 Roundcube 很容易。首先,請到 Roundcude 官網下載 Complete 的套件 (https://roundcube.net/download/)。

在下載時,我選擇 Stable version 中的 Complete (即完整套件)。您可以先複製連結網址,fetch 指令下戴。 或是在您個人電腦下載後,再以 SFTP 上傳到 FreeBSD。下載後,請解壓縮並將它搬到您的網頁目錄中。在以下指令中,我把 Roundcube 解開後,將它搬到我的網頁根目錄中 (/home/www),並將目錄更名為 mail。

#tar zxvf roundcubemail-1.4.6-complete.tar.gz
#mv roundcubemail-1.4.6 /home/www/mail

接著我們必須確定 Roundcube 可以讀寫它的暫存檔及日誌目錄。因為 Roundcude 是跑在網頁伺服器上,所以必須將目錄擁有者改成網頁伺服器的執行身份。

#chown -R www:www /home/www/mail

然後我們要建立 Roundcude 所使用的資料庫。如果您是使用 PostgreSQL,請使用下列指令,記得要把 /home/www/mail 換成您放 Roundcube 的目錄:

#createuser -P roundcube
#createdb -O roundcube -E UNICODE roundcubemail
#psql -U roundcube -f /home/www/mail/SQL/postgres.initial.sql roundcubemail
如果您是使用 MySQL,請使用下列指令,:

#mysql
>CREATE DATABASE roundcubemail CHARACTER SET utf8 COLLATE utf8_general_ci;
>CREATE USER roundcube@localhost IDENTIFIED BY 'password';
>GRANT ALL PRIVILEGES ON roundcubemail.* TO roundcube@localhost;
>quit
#mysql roundcubemail < /home/www/mail/SQL/mysql.initial.sql

最後,我們就可以打開瀏覽器連到 Roundcube 的設定頁面:https://your.domain.com/mail/installer。您只要依照頁面指示填入設定, 基本上只要確認資料庫設定正確即可。以下是我們需要修改的幾個項目:

設定完後,Roundcube 會自動在 /home/www/mail/config/ 目錄中建立 config.inc.php。接著,為了讓 Roundcube 可以自動建立它 所需要用到的預設郵件資料夾,請在 config.inc.php 中加入下列這一行:

$config['create_default_folders'] = true;

安裝完後,請將 installer 目錄移除:

#rm -rf /home/www/mail/installer

移除 installer 目錄後,您就可以連到 http://your.domain.com/mail 登入使用 Roundcube 了。

圖 14-3

14.4.2 在 Roundcube 中變更密碼

當您的系統中有其他使用者時,很自然的,我們必須提供使用者自行變更密碼的功能。在 Roundcube 中,它內建有變更密碼模組。 只要我們再進行一些設定,就可以讓使用者經由 Roundcube 在網頁中變更密碼。

因為 Roundcube 是一個經由 Apache 執行的網頁程式,而網頁程式本身並沒有權限執行系統指令以變更使用者密碼。 所以,我們必須安裝 poppwd 以輔助密碼變更。poppwd 會經由網路接收變更密碼的要求,所以我們要啟用 inetd 來接收 poppwd 的連線。

首先,請使用 Ports 安裝 poppwd:

#cd /usr/ports/mail/poppwd
#make install clean

接下來,請編輯 /etc/inetd.conf,加入下面這一行以支援 poppwd:

pop3pw stream tcp nowait root /usr/local/libexec/poppwd poppwd

因為我們安裝 poppwd 只是為了 Roundcube 變更密碼,並不打算讓其他人經由網路連線。所以,我們使用 hosts.allow 來限制只能由本機連線。請編輯 /etc/hosts.allow 在檔案的最上方加入下列內容:

... # hosts.allow 是 "First match wins",只要其中一行先符合規則,就不會再往下比對。 # 我們以下二行的設定是指只允許本地連結,其他 poppwd 連都拒絕。 poppwd : localhost : allow poppwd : ALL : deny # 在 hosts.allow 檔案最上方附近有下面這一段 ALL : ALL : allow,表示預設 # 允許任何連線。所以我們增加 poppwd 那二行必須在這個區塊的上方。 # Start by allowing everything (this prevents the rest of the file # from working, so remove it when you need protection). # The rules here work on a "First match wins" basis. ALL : ALL : allow ...

接著,我們就可以使用下列指令讓 inetd 在開機時執行,並立即啟動:

#sysrc inetd_enable="YES"
#service inetd start

最後,我們就可以設定 Roundcube 以啟動密碼變更模組了。請編輯 Roundcube 目錄中的 config/config.inc.php,在檔案最下方加入下列這一行:

... // ---------------------------------- // PLUGINS // ---------------------------------- // List of active plugins (in plugins/ directory) // 請找到 plugins 這一行,如果沒有,請自行加入下列這一行。我們在 plugins 中加入 // password 這個模組,以啟用密碼變更。 $config['plugins'] = array('archive', 'emoticons', 'password'); // 下面這一行設定密碼模組使用的密碼變更方式。 $config['password_driver'] = 'poppassd';

這樣就完成設定了。您可以登入 Roundcube,在 [設定]->[使用者密碼] 中修改密碼了。

圖 14-4

14.5 垃圾信及病毒防護

全拜電子郵件所賜,經由網際網路,我們可以很快的傳送郵件。然而,卻有人利用電子郵件從事令人不悅的廣告發送行為。 垃圾郵件可以說是目前網路上最令人厭惡的行為,相信常使用電子郵件的讀者們每天一定都會收到許多垃圾信件。 所有伺服器上處理的使用者都要處理這些垃圾郵件簡直是太浪費資源了。而且,除了垃圾信外, 郵件中所夾帶的病毒也十分危險,萬一有人不小心打開了具有病毒的信件,接下來又是另一場災難。

在設定 Postfix 時,我們有加入了檢查來源 IP 的功能,但這並不足以阻擋日新月異的垃圾郵件及病毒信。 面對這些垃圾信及病毒信,我們有更好的解決方式,就是使用 amavisd-new+Spamassassin+clamav。 amavisd-new 可以將 Postfix 的信轉給垃圾郵件分析軟體 Spamassasin 檢查,並將信件交給 ClamAV 掃瞄病毒。這三套軟體都是開放源始碼的免費軟體,很多網站都使用它來過濾垃圾信件。 您可以到 http://www.ijs.si/software/amavisd/ 找到更多關於 amavisd-new 的說明。

在架構方面,如下圖所示,我們要設 Postfix,讓它將信件交給 Amavisd 處理。處理完後,再轉回給 Postfix。 我們只要對原本安裝的 Postfix 做一點修改就可以支援 amavisd-new 了。

圖 14-5

安裝 amavisd-new 及 ClamAV

首先,請使用下列指令安裝防毒軟體 ClamAV :

#cd /usr/ports/security/clamav/
#make install clean

接著就可以安裝 amavisd-new 了:

#cd /usr/ports/security/amavisd-new/
#make install clean

在安裝 amavisd-new 時,會出現一個進階選項的視窗,請將 SpamAssassin 打勾。

設定 Postfix

安裝完後,我們先來設定 Postfix,讓 Postfix 在收到信後,先交給 Amavisd 進行內容過濾。 Postfix 會先把信使用 LMTP 協定經由 Port 10024 交給 Amavisd。在 Amavisd 處理完後,再使用 Port 10025 把信交回來給 Postfix。

請先編輯 /usr/local/etc/postfix/master.cf 在最下方加入下列設定:

... #Amavisd amavisfeed unix - - n - 2 lmtp -o lmtp_data_done_timeout=1200 -o lmtp_send_xforward_command=yes -o disable_dns_lookups=yes -o max_use=20 127.0.0.1:10025 inet n - n - - smtpd -o content_filter= -o smtpd_delay_reject=no -o smtpd_client_restrictions=permit_mynetworks,reject -o smtpd_helo_restrictions= -o smtpd_sender_restrictions= -o smtpd_recipient_restrictions=permit_mynetworks,reject -o smtpd_data_restrictions=reject_unauth_pipelining -o smtpd_end_of_data_restrictions= -o smtpd_restriction_classes= -o mynetworks=127.0.0.0/8 -o smtpd_error_sleep_time=0 -o smtpd_soft_error_limit=1001 -o smtpd_hard_error_limit=1000 -o smtpd_client_connection_count_limit=0 -o smtpd_client_connection_rate_limit=0 -o receive_override_options=no_header_body_checks,no_unknown_recipient_checks,no_milters -o local_header_rewrite_clients=

接著請編輯 /usr/local/etc/postfix/main.cf 在最下方加入下列設定:

# Amavisd content_filter = amavisfeed:[127.0.0.1]:10024

在設定好 Postfix 可以使用 Amavisd 後,接下來,我們就可以設定 Amavisd 了。

設定 Amavisd

amavisd-new 的設定檔在 /usr/local/etc/amavisd.conf。 我們要修改 $mydomain 的部份,將它設為郵件伺服器的網域名稱。另外,我們要設定使用掃毒伺服器 Clamd,以加速掃毒速度:

... # 設定郵件伺服器的網域名稱 $mydomain = 'twbsd.org'; # a convenient default for other settings ... # 因為 Amavisd 在使用 BDB 做資料庫時有點問題,所以我們把該功能關閉。 $enable_db = 0; # enable use of BerkeleyDB/libdb (SNMP and nanny) ... @av_scanners = ( ..... # 請找到 @av_scanners 區段中,再下面幾行有下列這些 ClamAV-clamd 的設定,我們將這四行的開頭註解 # 移除以啟用它。 # ### http://www.clamav.net/ ['ClamAV-clamd', \&ask_daemon, ["CONTSCAN {}\n", "/var/run/clamav/clamd.sock"], qr/\bOK$/m, qr/\bFOUND$/m, qr/^.*?: (?!Infected Archive)(.*) FOUND$/m ], # # NOTE: run clamd under the same user as amavisd - or run it under its own # # uid such as clamav, add user clamav to the amavis group, and then add # # AllowSupplementaryGroups to clamd.conf; # # NOTE: match socket name (LocalSocket) in clamav.conf to the socket name in # # this entry; when running chrooted one may prefer a socket under $MYHOME. ...

接著我們要將 ClamAV 執行的使用者加入 Amavisd 的群組 vscan 中。請編輯 /etc/group, 找到 vscan 並再最後面加上 clamav:

vscan:*:110:clamav

因為 Amavisd 在收到病毒信時,會寄一封通知信給 virusalert 這個使用者,所以我們編輯 /etc/aliases 加入 virusalert 的 alias:

virusalert: root

設定完 aliases 後,請使用下列指令更新資料:

#postalias /etc/aliases
設定定時維護工作

Spamassassin 和病毒掃瞄軟體一樣垃圾信定義檔。我們可以使用以下指令手動更新它的定義檔。

#sa-update -v

為了讓系統中的定義檔保持在較新的狀態,我們可以將上述指令加入 crontab 中。

另外,在 /usr/local/etc/amavisd.conf 中,參數 $QUARANTINEDIR 定義了 Amavisd 隔離的信件放在哪個目錄。 我們應該定期去刪除該目錄中較舊的檔案。

現在就讓我們編輯 /etc/crontab 並加入以下設定:

... # 在 PATH 最後加上 :/usr/local/bin。因為 sa-update 會使用 gpg 這個程式來檢查下載 # 的定義檔是否正確,所以我們將 gpg 的路徑 /usr/local/bin 加入搜尋指令的路徑中。 PATH=/etc:/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin ... # 更新 SpamAssassin 定義檔 12 7 * * * root /usr/local/bin/sa-update -v # 清理隔離目錄 0 1 * * 0 root /usr/bin/find /var/virusmails -ctime +7 -exec /bin/rm {} \;
正式啟動

在啟動 Amavisd 之前,我們先使用下列指令來下載 Spamassassin 的定義檔,及下載 ClamAV 的病毒碼:

#sa-update -v
#freshclam

接下來,請編輯 /etc/rc.conf 加入下面這幾行,讓系統在開機時啟動 Amavisd:

... # 啟動 Amavisd amavisd_enable="YES" # 啟動掃毒軟體 clamav_clamd_enable="YES" # 自動更新病毒碼 clamav_freshclam_enable="YES"

最後,我們就可以重新啟動 Postfix 及 Amavisd 了:

#service clamav-freshclam start
#service clamav-clamd start
#service amavisd start
#service postfix restart
測試

我們接下來就可以測試看看垃圾信的過濾功能是否正常。首先,我們測試一下病毒過濾。您可以從別的信箱使用純文字模式寄信給自已, 並在信件內容輸入下列這串文字:

X5O!P%@AP[4\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*

或者,您也可以使用 mail 這個指令來寄信給自已,輸入完後請按 Ctrl+D:

#mail youremail@example.com
Subject: This is a test mail
X5O!P%@AP[4\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*
^D

您會在 /var/log/maillog 中發現有 amavis Blocked INFECTED 的記錄, 而且 root 的信箱中也會出現掃到病毒的訊息 (因為我們把 virusalert 的信轉給 root)。

接著,我們測試一下垃圾信過濾。和前面的測試流程一樣,只是這次我們輸入下列這個字串:

XJS*C4JDBQADN1.NSBN3*2IDNEN*GTUBE-STANDARD-ANTI-UBE-TEST-EMAIL*C.34X

您會在 /var/log/maillog 中發現有 Passed SPAM 的記錄。而且 root 收到的信標題也會有 ***spam*** 的字樣。 如果以上的測試都成功,表示您的郵件伺服器已支援垃圾信及病毒過濾了!

14.6 郵件伺服器架構及問題處理

郵件伺服器架設好經過一段時間之後,您可能會遇到更多的使用者要求。接下來,我們將介紹一些郵件伺服器的管理上常見的任務及困難, 讓您對於郵件伺服器管理有更完整的知識。我們會先說明一下 Postfix 郵件存放位置及架構,這樣一來,在發生問題時, 我們才知道要去哪找問題。接著,我們會看一下信件原始檔結構,並研究如何處理收發信問題。

14.6.1 Postfix 郵件存放位置及架構

在深入了解郵件伺服器管理前,我們先來看一下 Postfix 如何收發信件。下圖為 Postfix 收發信件的流程及架構,黑色的線條箭頭代表信件尚未經由 Amavisd 過濾。 而橘色線條箭頭為已過濾的信件:

圖 14-6

當有信件從網路進來時,Postfix 的 SMTP 服務 (smtpd) 就會啟動以接收信件,並經由 cleanup 程式把信件放到 /var/spool/postfix/incoming 中。如果是本地端直接寄信 (例如系統每天自動檢查的信件, 或是從命令列執行 mail 指令),則會由 postdrop 把信放到 /var/spool/postfix/maildrop 中, 再由 pickup 程式交給 cleanup 放到 /var/spool/postfix/incoming 中。

信件進到 incoming 後的下一步就是開始送信的流程。Postfix 會把信放到 /var/spool/postfix/active 目錄中,接著 qmgr 會先將信經由 lmtp 交給 Amavisd 進行垃圾信過濾。過濾完後,再經由 smtpd 送回 Postfix 的 incoming 目錄。 最後,qmgr 會依不同的協定將信件送給本地使用者或是遠端的郵件伺服器。如果信件送出失敗且需要重送, 則會被放入 /var/spool/postfix/deferred 目錄中,系統會過一段時間後再重送。

在上圖中橘色方塊的程式都是由 master 這支程序 (daemon) 所控制。我們設定 master.conf 就是在控制這些 master 的呼叫的程序行為。

14.6.2 電子郵件原始結構

在管理郵件伺服器時,我們常會遇到使用者報怨信件無法送出、信件收不到、寄信出現錯誤等等。在遇到這類問題時, 我們必須具備問題追蹤的能力,以協助使用者解決寄信的問題。

在處理這些收發信件問題時,您可能必須查詢 DNS 的設定、了解郵件結構等。在說明如何處理收發信件問題前, 我們先來看一下電子郵件的原始檔案內容。

由於我們使用 Maildir 的郵件格式,所有的使用者新收到的信件會被放在使用者家目錄中的 Maildir/cur 目錄中。 這個目錄也就是使用者的 Inbox 目錄。Maildir/cur 目錄中包含了很多檔案,每一個檔案即是一封信件。 由於這些信件都是以純文字格式存放信件,管理者可以直接使用任何文書編輯軟體打開使用者的信箱。因此,管理者本身的操守很重要, 否則所有人的機密都會被看見。

為了了解一封信的結構,我們還是要看一下信件的內容。您可以打開自己家目錄中 Maildir/cur 裡的信件, 或是在收信軟體中檢視郵件原始檔。我們可以看到一個郵件原始資料如下:

# Return-Path 表示要回信則會回給 notification@synology.com Return-Path: <notification@synology.com> # Received 的部份,最上面是最後一個收到的伺服器。以這個例子,我們可以 # 看到它是由 twbsd.org 還給自已 (localhost [127.0.0.1])。這是 Amavisd # 掃瞄完後送回給 Postfix 的記錄。 Received: from twbsd.org (localhost [127.0.0.1]) by twbsd.org (Postfix) with ESMTP id F234EDF04B9 for <alex@twbsd.org>; Sat, 18 Jul 2015 12:28:25 +0800 (CST) # 這些是 Amavisd 所加的掃瞄結果註記。 X-Quarantine-ID: <wTmCTGeOTwWR> X-Virus-Scanned: amavisd-new at twbsd.org X-Amavis-Alert: BAD HEADER SECTION, Duplicate header field: "Date" # 這一個 Received 是由 twbsd.org 送給自已 port 10024,也就是 Postfix # 把信交給 Amavisd 掃瞄。 Received: from twbsd.org ([127.0.0.1]) by twbsd.org (twbsd.org [127.0.0.1]) (amavisd-new, port 10024) with LMTP id wTmCTGeOTwWR for <alex@twbsd.org>; Sat, 18 Jul 2015 12:28:11 +0800 (CST) # 信件再交給 twbsd.org 前,是由 synoportal.com 發出信件,它的 IP 是 60.251.87.130 Received: from synoportal.com (synoportal.com [60.251.87.130]) by twbsd.org (Postfix) with ESMTP id 53342DF02C7 for <alex@twbsd.org>; Sat, 18 Jul 2015 12:28:11 +0800 (CST) # 信件最原始是由 DiskStation,IP 60.251.87.130 發出 Received: from DiskStation (MyDSCenter [60.251.87.130]) (Authenticated sender: admin) by synoportal.com (Postfix) with ESMTPA id 1E8EC11C0E78 for <alex@twbsd.org>; Sat, 18 Jul 2015 12:28:12 +0800 (CST) # Date 是寄信的時間。 Date: Sat, 18 Jul 2015 12:28:12 +0800 # From 是寄件者的名稱及 Email。 From: "Synology eNews" <notification@synology.com> # 這是收件者的信箱。 To: <alex@twbsd.org> # Subject 是本封信件的主旨。 Subject: Synology DSM 5.2 Important Update # Message-ID 是由發信軟體所產的郵件編號。 Message-ID: <a4e1c0ac00c1437e9a3aff387a449758@MyDSCenter> # 此封郵件所使用的 MIME 版本。 MIME-Version: 1.0 # 郵件內容格式。 Content-Type: multipart/alternative; boundary="b1_a4e1c0ac00c1437e9a3aff387a449758" Content-Transfer-Encoding: 8bit # 以下為郵件本文 ... 略 ...

我們可以從郵件的標頭中看到信件真正的來源。有的郵件來源可能會假造,我們也可以從郵件的標頭中看出來。 了解一個信件的結構後,對於之後處理收發信問題會大有幫助。

14.6.3 發信問題處理

電子郵件在現在的企業中使用非常頻繁,很多公司幾乎所有事務都經由電子郵件處理,收發信不正常往往是 MIS 人員的惡夢。 很多時候問題可能不是出現在郵件伺服器本身,而是網路設定、DNS 問題、或是對方伺服器的問題。當您遇到收發信件問題時, 就必須要從系統記錄、發信軟體中查出蛛絲馬跡。在檢查問題之前,請先確認您的郵件伺服器的 DNS 設定沒問題, 而且郵件伺服器 IP 和主機名稱正反解都正確。DNS 設定不正常的伺服器往往是不能收發信件的主因。

在發信問題方面,如果您使用發信軟體寄不出信件,請先檢查發信軟體所秀出的訊息,再找解決之道。 通常發信問題可以分為二類,一種是在使用客戶端軟體 (如 Outlook、Thunderbird) 送信時就已經送不出去,另一種是信送出了, 但對方沒收到。第一種問題比較好解決,我們只要看客戶端軟體的錯誤訊息即可看出端倪。以下列訊息為例:

圖 14-7

我們可以看到錯誤訊息中有「Relay access denied」,很有可能這一台伺服器必須經過身份認證後才可以使用, 我們只要在送信設定中使用身份認證即可。在郵件客戶的訊息中,也有可能出現類似 DNS 找不到、主機找不到、使用者不存在等問題。 我們只要依這些訊息來查看設定、Email 位址,即可找到原因。

第二種問題是信件寄出了,但是對方沒收到。這種情形,我們就必須要多花點心力了。 首先,我們先到伺服器上使用 mailq 查看信件是否在佇列中。 如果在,則查看一下送出去出的原因,並依錯誤訊息解決問題。如果從錯誤訊息中看不出問題, 則可以查閱 /var/log/maillog,並找出該信件的寄送訊息:

Feb 8 18:54:18 twbsd postfix/smtp[33651]: ADBE4209DF0: to=, relay=none, delay=21, delays=21/0.06/0.05/0, dsn=5.4.4, status=bounced (Host or domain name not found. Name service error for name=abcdid234.com type=A: Host not found)

以上述範例為例,就是因為找不到 abcdid234.com 這台主機。這時候,我們可以手動使用 nslookup 查找該主機, 並檢查 DNS 的設定是否有問題。如果是 DNS 主機的問題,則可以更換 DNS 伺服器設定。

如果收件者的伺服器有安裝防垃圾信軟體,有的時候我們的伺服器所使用的 IP 可能會因為某些列為垃圾信。 在發信後,您可能會收到下列退信:

----- The following addresses had permanent fatal errors ----- <jousset@sultant.com> (reason: 554 EMail from mailserver at 10.22.102.129 is refused. See http://spamblock.outblaze.com/10.22.102.129) ----- Transcript of session follows ----- ... while talking to sultant-com.outblaze.com.: >>> DATA <<< 554 EMail from mailserver at 10.22.102.129 is refused. See http://spamblock.outblaze.com/10.22.102.129 554 5.0.0 Service unavailable <<< 554 Error: no valid recipients

這時候我們就必須依該信件指示,到該黑名單網站中要求對方將我們的 IP 從黑名單中移除。

如果從 /var/log/maillog 中確認信已經從本機寄出而對方還是沒收到, 則接下來就要請對方 MIS 人員查看對方伺服器是否有問題了。

總結關於發信問題處理步驟如下:

14.6.4 收信問題處理

在收信問題方面,和發信問題一樣,最關鍵的還是 DNS 設定。我們必須先檢查客戶端所使用的電腦是不是可以正常的找到郵件伺服器。 如果找不到,則必須修改 DNS 設定。

接下來,必須確認客戶端的發信軟體有連到伺服器,並可以正常使用 POP3 或 IMAP。如果在連線時出現錯誤, 您一樣可以從 /var/log/maillog 中看出問題。

如果有人抱怨一直沒有收到客戶寄來的信,我們可以從 /var/log/maillog 中找出該寄件者到底有沒有將信件寄到我們的伺服器。如果沒有,則可以請對方檢查郵件信箱是否正確、對方伺服器中是否有其它訊息。

14.6.5 郵件佇列管理

當信件寄不出去時,我們可以使用 mailq 這個指令來看看為什麼信會卡住。

#mailq -Queue ID- --Size-- ----Arrival Time---- -Sender/Recipient-------
628B3DEFFF0 1184 Mon Jul 6 16:39:49 MAILER-DAEMON
         (connect to medusa.nn.com[209.254.135.7]:25: Operation timed out)
                 cjns@nn.com
18D0ADEFF53 1168 Sun Jul 5 06:40:02 MAILER-DAEMON
         (host aoe.org[69.162.139.202] said: 451 Temporary local problem - please try later (in reply to RCPT TO command))
                 yuwizb@aoe.org
80DA6DF008C 1169 Tue Jul 7 21:07:29 MAILER-DAEMON
         (connect to 88jt.com[42.159.133.101]:25: Operation timed out)
                 up@88jt.com

-- 4 Kbytes in 3 Requests.

我們可以看到共有三封信件在郵件佇列中。第一封信件的 Queue ID 是 628B3DEFFF0。我們可以使用下列指令去查看該信件內容:

#postcat -q 628B3DEFFF0
*** ENVELOPE RECORDS deferred/6/628B3DEFFF0 ***
message_size: 1184 164 1 0 962
message_arrival_time: Mon Jul 6 16:39:49 2015
sender:
create_time: Mon Jul 6 16:39:49 2015
named_attribute: rewrite_context=local
sender_fullname: MailScanner
*** MESSAGE CONTENTS deferred/6/628B3DEFFF0 ***
Received: by twbsd.org (Postfix, from userid 125)
    id 90DA0DEFFE6; Mon, 6 Jul 2015 16:39:49 +0800 (CST)
From: "MailScanner" <postmaster@twbsd.org>
To: cjns@nn.com
Subject: Warning: E-mail viruses detected
X-twbsd-MailScanner: generated, Found to be clean
Message-Id: <20150706083949.90DA0DEFFE6@twbsd.org>
Date: Mon, 6 Jul 2015 16:39:49 +0800 (CST)

Our e-mail content detector has just been triggered by a message you sent:
  To: root@twbsd.org
  Subject: Re???????????481875
  Date: Mon Jul 6 16:39:35 2015

One or more of the attachments (msg-61396-2.txt) are on
the list of unacceptable attachments for this site and will not have
been delivered.

Consider renaming the files to avoid this constraint.

The virus detector said this about the message:
Report: Report: MailScanner: No programs allowed (msg-61396-2.txt)

在郵件佇列中的信 Postfix 會自動重新送出,您可以可使用下列指令立即重新送出佇列中的信:

#postqueue -f

如果您想刪除郵件佇列中的信件,則可以使用 mailq 看一下它的 Queue ID 後。再使用下列指令刪除該郵件:

#postsuper -d 80DA6DF008C
postsuper: 80DA6DF008C: removed
postsuper: Deleted: 1 message

如果您要刪除所有在佇列中的信,則可以使用下列指令:

#postsuper -d ALL
postsuper: Deleted: 2 messages
14.6.6 郵件別名及自動轉寄

當有同事離職時,我們常會被要求將該同事的信件轉給某人。這種自動轉寄功能的設定很容易, 我們只要設定 /etc/aliases 即可。

/etc/aliases 是用以告知郵件伺服器要將信轉給哪個使用者或是交由哪個程式處理。 aliases 這個檔案是用來設定郵件的別名,也就是可以設定要將某人的信件轉給其他地方(人員或程式), 你也可以同時將某人的信轉給很多人。當郵件伺服器收到信時,會一行一行比對,當第一行符合後,就不會再繼續下去,所以應注意優先順序。

我們來看下列幾個設定的範例:

#本檔案的語法開頭的 "#" 代表該行是註解,大小寫都視為一樣。 # 範例一 root: alex # 範例二 john: alex,john # 範例三 webmanager: alex,jack,jim@other.hostname.com # 範例四 nobody: /dev/null # 範例五 homework: |/usr/local/bin/homework.sh # 範例六 olduser: :include: /usr/local/olduser_list

aliases 檔中將很多東西都轉向 root,因此你可以去讀 root 的信箱或是將 root 的信轉給別的地方,下面這一行是將 root 的信都轉給 my@my.domain:

root: me@my.domain

當郵件無法送出被退回時給使用者時,都是以 MAILER-DEAMON 為帳號寄出。因為使用者可能會回覆那封被退回的信,所以這個別名是必備的。而 postmaster 則負責處理所有關於郵件問題的信件,因此也是必備的,一定要保留下面二行,這是必要的系統基本設定:

MAILER-DAEMON: postmaster postmaster: root

請注意,修改完 /etc/aliases 後,我們必須使用下列指令來讓所做的修改在 Postfix 中發生作用:

#postalias /etc/aliases
如果是使用 Sendmail,更新別名資料庫的指令為 newaliases。 由於 Postfix 在設計上就是要和 Sendmail 相容,因此,它也有一個 newaliases 的指令位於 /usr/local/bin/newaliases,它的效果就和 "postalias /etc/aliases" 一樣。 在安裝 Postfix 時,我們修改了 mailer.conf, 以讓使用者在輸入舊的 Sendmail 指令時能自動導向 Postfix 的相容指令。所以,您也可以只輸入 newaliases 來更新別名。
14.7 寄件者來源驗證

由於 SMTP 協定的缺陷,寄件者 (From) 是可以輕易被假造的。現今許多的垃圾郵件都會偽造寄件者。例如,以下是使用 telnet 連到我們的郵件伺服器並假造 From 是 bill@microsoft.com。下列內容中,粗體字是我們輸入的指令,數字開頭則是伺服器的回應。

#telnet localhost 25
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
220 twbsd.org ESMTP Postfix
HELO localhost
250 twbsd.org
MAIL FROM:<bill@microsoft.com>
250 2.1.0 Ok
RCPT TO:<alex@twbsd.org>
250 2.1.5 Ok
DATA
354 End data with <CR><LF>.<CR><LF>
Subject: This is a test

This is the content
.
250 2.0.0 Ok: queued as 5A91EDEE194
quit
221 2.0.0 Bye
Connection closed by foreign host.

如果有人假冒您的公司或組織發送信件,不僅 IT 人員必須浪費時間去釐清信件是否真的由其所屬機構發出, 被假冒的公司也會受到商譽損失。為了解決寄件者假冒的問題,我們可以使用 SPF 及 DKIM 的電子郵件驗證技術來進行寄件者的驗證。

14.7.1 為網域加上 SPF

SPF (Sender Policy Framework) 是一個公開的協定,它可以讓網域擁有者經由 DNS 設定該網域發信所會使用的伺服器名稱或 IP。 如此一來,收信的伺服器就可以比對來源 IP 是否和該網域允許的發信伺服器一致,以避免非該網域擁有者偽裝成他人的 email 位址。

圖 14-8

在還沒有為您的網域加入 SPF 設定之前,如果您寄信給 Gmail 或 Yahoo,你可以在 Gmail 的信件標頭中看到下列這一行:

Received-SPF: neutral (google.com: 1.34.24.68 is neither permitted nor denied by best guess record for domain of alex@example.net) client-ip=1.34.24.68;

要為我們的網域啟用 SPF 很簡單,只要在 DNS 伺服器上新增一筆 TXT record 指定可能發信的伺服器即可。以下是一個 SPF 的設定範例:

example.net. IN TXT "v=spf1 a mx ip4:1.2.33.44 a:support.example.net include:_spf.google.com ~all"

以下為每個欄位的說明:

v=spf1 表示使用 SPF version 1。
a example.net 由 DNS 解析出來的 IP 可以是合法的寄信伺服器。
mx example.net DNS 的 MX 記錄中的收信伺服器也都可以是合法的寄信伺服器。
ip4:1.2.33.44 IP4 表示您也允許該 IP 寄出信件。
a:support.example.net support.example.net 也可以是合法的寄信伺服器。
include:_spf.google.com 如果您使用 Gmail 做主機代管,則設定所有 Google 伺服器都可以合法寄信。
~all all 具有三個可用的參數:
  • -:除了上面所列的寄件者以外,不接受來自其它伺服器發出的郵件;標示為 Hard Fail。
  • ~:只接受來自上述其中一個寄件者的任何電子郵件;如果不符,還是允許電子郵件但標示為 Soft Fail。
  • ?:則表示中立,代表可能還有其它伺服器會送信,收件伺服器還是會接收該信件。

我們現在可以來為自己的網域加上 SPF 設定了。如果您是自行架設 DNS 伺服器,只要在 ZONE file 中加入下列內容。 它表示我們的網域允許網域本身的 IP 及所有 MX 中的伺服器寄信。

@ IN TXT "v=spf1 a mx ~all"

如果您的 DNS 是交由 Godaddy 等 DNS 代管,在它們的網域上設定 DNS 的頁面應該可以新增一筆 TXT 的資料。以 Godaddy 為例, 以下是它的設定畫面:

圖 14-9

在啟用了 SPF 之後,再寄次信給 Gmail 或 Yahoo,你可以在 Gmail 中發現信件標頭中 SPF 已啟用:

Received-SPF: pass (google.com: domain of alex@example.net designates 1.34.24.68 as permitted sender) client-ip=1.34.24.68;

如果您的 SPF 設定無法正常運作,你可以查詢看看 DNS 設定是否正確。我們可以使用下列指令來查詢 DNS 中 TXT 的設定:

#host -t TXT example.net
example.net descriptive text "v=spf1 a mx ~all"
14.7.2 收信時檢查 SPF

我們也可以在 Postfix 中啟動 SPF 的檢查。首先,請安裝 SPF 檢查的外掛程式:

#cd /usr/ports/mail/postfix-policyd-spf-perl
#make install clean

接著,請編輯 /usr/local/etc/postfix/master.cf,在最下方加入下列設定:

spf-policy unix - n n - 0 spawn user=nobody argv=/usr/local/libexec/postfix-policyd-spf-perl

接著,在 /usr/local/etc/postfix/main.cf 中加入下列設定:

... smtpd_client_restrictions = check_client_access hash:/usr/local/etc/postfix/access, permit_mynetworks, permit_sasl_authenticated, reject_unauth_destination, # reject_rbl_client sbl-xbl.spamhaus.org, # reject_rbl_client zen.spamhaus.org, # reject_rbl_client bl.spamcop.net, # reject_rbl_client cbl.abuseat.org, check_policy_service unix:private/spf-policy permit spf-policy_time_limit = 3600

我們在 smtpd_client_restrictions 設定的最下方 (permit 之前,且在 reject_unauth_destination 之後) 加入了 check_policy_service。如果我們希望 Spamassassin 能使用 SPF 來協助判斷垃圾信, 則可以修改 /usr/local/etc/mail/spamassassin/init.pre,將下列這一行的註解移除:

... # SPF - perform SPF verification. # loadplugin Mail::SpamAssassin::Plugin::SPF

設定好之後,我們就可以重新啟動 Postfix 了:

#service postfix restart

接著,我們就可以使用 Gmail 寄信給自己試試看。您會發現信件標頭會有下列訊息:

Received-SPF: pass (gmail.com ... _spf.google.com: Sender is authorized to use 'yourname@gmail.com' in 'mfrom' identity (mechanism 'include:_netblocks.google.com' matched)) receiver=localhost; identity=mailfrom; envelope-from="yourname@gmail.com"; helo=mail-ob0-f170.google.com; client-ip=209.85.214.170

如果是假造的寄件者,則標頭會出現下列內容:

X-Spam-Status: Yes, score=10.326 tagged_above=2 required=6.2 tests=[FSL_HELO_NON_FQDN_1=0.001, HELO_LOCALHOST=3.603, MISSING_DATE=1.396, MISSING_FROM=1, MISSING_HEADERS=1.207, MISSING_MID=0.14, RCVD_IN_BRBL_LASTEXT=1.644, RDNS_DYNAMIC=0.363, SPF_SOFTFAIL=0.972] autolearn=no autolearn_force=no ... Received-SPF: softfail (gmail.com ... _spf.google.com: Sender is not authorized by default to use 'alex@gmail.com' in 'mfrom' identity, however domain is not currently prepared for false failures (mechanism '~all' matched)) receiver=localhost; identity=mailfrom; envelope-from="alex@gmail.com"; helo=localhost; client-ip=125.227.152.103

當 SPF 判斷出 Softfail 的情形時,Spamassassin 只是將信件垃圾信的分數加分,但不直接拒絶該信件。 如果您想要在 Softfail 時也直接拒絶該信件,我們可以在 /usr/local/etc/postfix/main.cf 加上下列設定:

header_checks = regexp:/usr/local/etc/postfix/header_checks

接著,請新增檔案 /usr/local/etc/postfix/header_checks 內容如下,並重新啟動 Postfix:

/^Received-SPF: softfail/ REJECT
14.7.3 使用 DKIM 驗證電子郵件

除了使用 SPF 來驗證寄件伺服器是否合法外,我們還可以使用 DKIM 驗證寄件者的正確性。DKIM (DomainKeys Identified Mail) 可以讓我們在郵件標頭中加上數位「簽名」,如此一來,收件者只要檢查郵件中是否含有我們網域的簽名, 即可確認該郵件的寄件者地址確實屬於該網域中的地址,而且未在寄件途中遭到竄改。

圖 14-10

DKIM 是先產生一把網域金鑰放在郵件伺服器上,再將公開金鑰放到 DNS 伺服器上。在送信時,郵件伺服器會在信件標頭簽章。 收信對方的伺服器收到信件後,會去 DNS 上查詢 DKIM 的公開金鑰,並用以驗證信上的簽章是否正確。

在設定方面,Postfix 可以經由 Amavisd-new 來支援 DKIM。如果您尚未安裝設定 amavisd-new,請先參考前面章節安裝 Amavisd-new。

產生金鑰並設定 DNS

首先,我們要產生一把網域金鑰。請使用下列指令 (請把 example.net 換成您的網域名稱):

#amavisd genrsa /usr/local/etc/postfix/example.net.dkim.pem

接著,請編輯 /usr/local/etc/amavisd.conf,找到 enable_dkim_signing 的部份, 並在下方加入 dkim_key 等下列內容:

... $enable_dkim_verification = 1; $enable_dkim_signing = 1; dkim_key('example.net', 'mail', '/usr/local/etc/postfix/example.net.dkim.pem'); @dkim_signature_options_bysender_maps = ( { '.' => { ttl => 10*24*3600, c => 'relaxed/simple' } } );

然後,請使用下列指令顯示公鑰:

#amavisd showkeys
; key#1 1024 bits, i=mail, d=example.net, /usr/local/etc/postfix/example.net.dkim.pem
mail._domainkey.example.net.     3600 TXT (
   "v=DKIM1; p="
   "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCai4mQScFc+bAxPf/as9qCTtiP"
   "KnRrkFx1Jlr6N38vS5RK3oKZgX+Oih4ti61GxotodAO0lLXNUR8WwrdetAcfzXQF"
   "uTkabpO6sW8oWvj66dlNBm9n5lt1oyEL1ncPzoSMQ5dulVg83VeTc8eL663SdDpw"
   "tV1LpEOBimWmgRILWwIDAQAB")

您可以將上面所輸出的內容加入 DNS 伺服器的 ZONE file 中。如果您使用 Godaddy 等第三方 DNS 服務,你可以在 Godaddy 的 DNS 管理介面新增一筆 host 為 mail._domainkey 的 TXT 記錄,並將上面 "v=DKIM1; p=MIGfMA0GC..." 的內容,如下所示:

圖 14-11

設定完 DNS 後,請執行下列指令測試 DKIM 金鑰是否設定正確。它會連到您的 DNS 伺服器取回公開金鑰並和系統中的私鑰做比對:

#amavisd testkeys
TESTING#1 example.net: mail._domainkey.example.net => pass

您也可以使用下列指令和 DNS 伺服器查詢金鑰 (請將 example.net 換成您的網域名稱):

#host -t TXT mail._domainkey.example.net
mail._domainkey.examle.net descriptive text "v=DKIM1; p=MIGfMA0GCSqGSIb3DQEBAQU
AA4GNADCBiQKBgQCai4mQScac+bAxPf/as9qCTtiPKnRrkFx1Jlr6N38vS5RK3oKZgX+Oih4ti61Gx
otodAO0lLXNUR8WwrdetAcfzXQFuTkabpO6sW8oWvj66dlNBm9n5lt1oyEL1ncPzoSMQ5dulVg83Ve
Tc8eL663SdDpwtV1LpEOBimWmgRILWwIDAQAB"
設定郵件伺服器

當 DNS 伺服器及金鑰設定完成後,我們就可以設定郵件伺服器了。我們要利用 Amavisd-new 來進行 DKIM 的簽署及認證。為了讓 Amavisd 可以分辦出什麼信件要加上簽名、什麼信件只要檢查 DKIM,我們必須將這二種信分開。所以,在 Postfix 中,我們會設定將內部的信送給 Amavisd 的 port 10026,並將外部來的信送給 Amavisd 的 port 10024,如下圖所示:

圖 14-12

首先,請編輯 /usr/local/etc/postfix/main.cf,加入下列內容:

... # 預設的 Content Filter。 content_filter = amavisfeed:[127.0.0.1]:10024 # 加入 smtpd_sender_restrictions 的規則。我們在 tag_as_originating.re 這個檔案中,將 # content_filter 改成 port 10026,對在 tag_as_foreign.re 把 port 改成 10025。由於 # smtpd_sender_restrictions 規則是 "先入為主" (first match wins),只要符合規則就會離開。 # 以下的設定如果是我們內部網路發出來的信件,在第一個 check_sender_access 中,content filter 會 # 被改成 port 10026,然後因為 permit_mynetworks 已允許寄信,系統不會再往下執行其它的判斷。 # 如果是外面進來的信,在第一步 check_sender_access 會把 ports 改成 10026,因為 permit_mynetworks、 # permit_sasl_authenticated 等都不吻合,所以會執行到第二個 check_sender_access 並將 content filter # port 改成 10024。如此一來,我們就可以分開二條路了。 smtpd_sender_restrictions = check_sender_access regexp:/usr/local/etc/postfix/tag_as_originating.re permit_mynetworks permit_sasl_authenticated permit_tls_clientcerts check_sender_access regexp:/usr/local/etc/postfix/tag_as_foreign.re

接著新增 /usr/local/etc/postfix/tag_as_originating.re 內容如下:

/^/ FILTER amavisfeed:[127.0.0.1]:10026

接著新增 /usr/local/etc/postfix/tag_as_foreign.re 內容如下:

/^/ FILTER amavisfeed:[127.0.0.1]:10024

在 Postfix 的 /usr/local/etc/postfix/master.cf中,我們之前已經設定好了 amavisfeed 及 port 10025,現在我們只要新增 port 10027,如下列最下方的內容:

... # Amavisd amavisfeed unix - - n - 2 lmtp -o lmtp_data_done_timeout=1200 -o lmtp_send_xforward_command=yes -o disable_dns_lookups=yes -o max_use=20 127.0.0.1:10025 inet n - n - - smtpd -o content_filter= -o smtpd_delay_reject=no -o smtpd_client_restrictions=permit_mynetworks,reject -o smtpd_helo_restrictions= -o smtpd_sender_restrictions= -o smtpd_recipient_restrictions=permit_mynetworks,reject -o smtpd_data_restrictions=reject_unauth_pipelining -o smtpd_end_of_data_restrictions= -o smtpd_restriction_classes= -o mynetworks=127.0.0.0/8 -o smtpd_error_sleep_time=0 -o smtpd_soft_error_limit=1001 -o smtpd_hard_error_limit=1000 -o smtpd_client_connection_count_limit=0 -o smtpd_client_connection_rate_limit=0 -o receive_override_options=no_header_body_checks,no_unknown_recipient_checks,no_milters -o local_header_rewrite_clients= spf-policy unix - n n - 0 spawn user=nobody argv=/usr/local/libexec/postfix-policyd-spf-perl 127.0.0.1:10027 inet n - n - - smtpd -o content_filter= -o smtpd_delay_reject=no -o smtpd_client_restrictions=permit_mynetworks,reject -o smtpd_helo_restrictions= -o smtpd_sender_restrictions= -o smtpd_recipient_restrictions=permit_mynetworks,reject -o smtpd_data_restrictions=reject_unauth_pipelining -o smtpd_end_of_data_restrictions= -o smtpd_restriction_classes= -o mynetworks=127.0.0.0/8 -o smtpd_error_sleep_time=0 -o smtpd_soft_error_limit=1001 -o smtpd_hard_error_limit=1000 -o smtpd_client_connection_count_limit=0 -o smtpd_client_connection_rate_limit=0 -o receive_override_options=no_header_body_checks,no_unknown_recipient_checks,no_milters -o local_header_rewrite_clients=

接著,我們來編輯 /usr/local/etc/amavisd.conf 讓它針對二個不同的 port 做不同行為 (一個簽署,一個檢查):

.... # 我們原本以設定了下列項目以開啟 DKIM 的檢查及簽署。 $enable_dkim_verification = 1; $enable_dkim_signing = 1; dkim_key('example.net', 'mail', '/usr/local/etc/postfix/example.net.dkim.pem'); @dkim_signature_options_bysender_maps = ( { '.' => { ttl => 10*24*3600, c => 'relaxed/simple' } } ); # 找到 inet_socket_port 的部份,把 10024 那一行註解起來,並將它下一行註解移除以開啟二個 port。 #$inet_socket_port = 10024; # listen on this local TCP port(s) $inet_socket_port = [10024,10026]; # listen on multiple TCP ports ... # 下列針對 port 10026 進來的信都當作自己伺服器的信並進行簽署。 # 這幾行是原本 amavisd.conf 就有的內容,不需修改。 $interface_policy{'10026'} = 'ORIGINATING'; $policy_bank{'ORIGINATING'} = { # mail supposedly originating from our users originating => 1, # declare that mail was submitted by our smtp client allow_disclaimers => 1, # enables disclaimer insertion if available # notify administrator of locally originating malware virus_admin_maps => ["virusalert\@$mydomain"], spam_admin_maps => ["virusalert\@$mydomain"], warnbadhsender => 1, # forward to a smtpd service providing DKIM signing service forward_method => 'smtp:[127.0.0.1]:10027', # force MTA conversion to 7-bit (e.g. before DKIM signing) smtpd_discard_ehlo_keywords => ['8BITMIME'], bypass_banned_checks_maps => [1], # allow sending any file names and types terminate_dsn_on_notify_success => 0, # don't remove NOTIFY=SUCCESS option }; ... # 將以下二行註解移除,以讓 Amavisd 可以使用二個 port 和 Postfix 溝通。 $notify_method = 'smtp:[127.0.0.1]:10025'; $forward_method = 'smtp:[127.0.0.1]:10025'; # set to undef with milter! ...

這樣設定就完成了。我們使用下列指令來重新啟動 Postfix 及 Amavisd-new:

#service amavisd restart
#service postfix restart

您現在可以使用您的伺服器發信到 Gmail,在郵件的標頭中,我們可以看到下列內容,表示 DKIM 以啟用:

... Authentication-Results: mx.google.com; spf=pass (google.com: domain of alex@example.net designates 1.34.24.68 as permitted sender) smtp.mail=alex@example.net; dkim=pass header.i=@example.net DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=example.net; h= content-type:content-type:subject:subject:mime-version :user-agent:from:from:date:date:message-id:received:received; s= mail; t=1437734352; x=1439548753; bh=z/PX8z9McKoTdB8+OMi9Euk3ngZ +Ent0iaLyKpfKfmY=; b=FEYviYSnrrRH+EGqvmofOzHR0dLeshW9k+9pO2GxjCB r2JynN9sjdDGxEB55JbB6a5FTY/fvEg9zhNUMFVvN9E60RjfDPgCdewAgSGCVnz+ CIg+FOxvstKHwW8+TBGWFN/ziLzHiX2tnaIc5MA9usbNv7aEI8EgNbWb0hGIRdfw
14.7.4 寄件者名稱限制

我們已經設定好 SPF 及 DKIM,該他人難以假裝以我們的網域名稱發信。不過,如果是同一個網域的使用者,使用者 A 還是可以偽裝成使用者 B。以一間公司而言,某一個員工就可以偽裝成總經理發信叫大家明天不必上班。 這聽起來就是一個安全性的漏洞。還好我們可以限制從我們伺服器寄出的信使用者的正確性。首先, 我們可以強制使用者一定要登入才可以發信。而且寄件者一定要看登入的使用者名稱一致。如此一來, 使用者就不能再偽裝成別人了。

要達到這個目的,我們先新增一個檔案在 /usr/local/etc/postfix/login_maps.pcre 內容如下:

/^(.*)@example\.net$/ ${1}

請把上列 example.net 改成您的網域名稱。接著修改 /usr/local/etc/postfix/main.cf 加入下列內容即可:

... smtpd_sender_login_maps = pcre:/usr/local/etc/postfix/login_maps.pcre # 若您沒有設定 DKIM,原本沒有 smtpd_sender_restrictions,則加入下列這一行。 smtpd_sender_restrictions = reject_authenticated_sender_login_mismatch # 若您有設定 DKIM,smtpd_sender_restrictions 已有內容,則將 reject_authenticated_sender_login_mismatch # 加入下列位置: smtpd_sender_restrictions = check_sender_access regexp:/usr/local/etc/postfix/tag_as_originating.re reject_authenticated_sender_login_mismatch permit_mynetworks permit_sasl_authenticated permit_tls_clientcerts check_sender_access regexp:/usr/local/etc/postfix/tag_as_foreign.re

接著重新啟動 Postfix 即可。

#service postfix restart