http://phorum.study-area.org/viewtopic.php?t=40579
Sendmail Domain Key 教學
歡迎轉載 ,但不得作為商業用途
作者: abelyang
最後修正時間: 2006/07/24 00:10
轉載時請保持此一宣告
Sendmail + DomainKey 實作分享
前言
Domain Key (DKIM) 目前尚無標準(RFC) 文件,目前 IETF Draft 只到 04 版(最終到 -06),估計還要一年多才會形成 RFC,
相關訊息可參考 IETF DKIM Working Group (http://www.ietf.org/html.charters/dkim-charter.html), 及
Domain Key 網站 ( http://mipassoc.org/dkim/ ), 這個網站可以找到各種 MTA 如何 support DKIM 的文件及 Source
Domain Key 主要是由 Yahoo 所推的網域名稱和郵件伺服器間認證方式, Server 所發出來的信件使用 private key
加密必要的表頭(Ex: From:Subject:Date),目的 MTA 在收到信件時取出這些表頭,以 public key (從 DNS 中取出,
後述)進行表頭驗證,從驗證的結果中得到一個 return 值,並針對這些值由目的 MTA 決定動作 (Accept/Reject/Discare..),
所以, MTA 要支援 Domain Key, 不同的 MTA 做法稍有不同,僅以個人較熟悉之 sendmail 進行介紹,以供大家參考.
(據聞 postfix 也支援 Milter , 但個人未用過 postfix,故留待有緣人自己研究了,或上述專門介紹 DKIM 的網站中,
也有各種 MTA 的做法).
最後,值得一提的是, Yahoo 目前使用的 DKIM 版本是 02 版,而目前最新的 Draft 到 04 版,最近的 DKIM Milter 則支援
0.3 版,所以,我們的介紹是配合 Yahoo 使用 DKIM 能支援 02 版的 dk-filter 0.4.1
1. sendmail 準備工作
1.1 sendmail 需支援 Milter
不論 DKIM 也好, SPF 也罷,在 Sendmail 中實現都是以 Milter (Mail Fitler) 來做, Milter 的功能是在 SMTP 協商
的過程式去連接一個外部程式進行檢驗,例如 ehlo/mail from/rcpt to/data 等,每個步驟的過程都可以連接一個外部程
式進行檢驗及行為處理,所以,若 user 有需要可以修改 Envelpe To, Header 等,而 DKIM 的 filter 主要的工作是進行
加 Header 及取 Header 驗證的工作,故只有在 Data 上做文章. 所以您的 sendmail 有沒有支援 Milter 決定了你可否
直接使用 DKIM filter (dk-filter),或是必需重新安裝 sendmail
代碼:
# 檢驗 sendmail 是否支援 Milter (-d0 表示要看 Complier 參數,不同的 -dX.Y 各有不同意義)
[root@eai1 mail]# sendmail -d0 Version 8.13.7
Compiled with: DNSMAP LOG MAP_REGEX MATCHGECOS MILTER MIME7TO8 MIME8TO7
NAMED_BIND NETINET NETUNIX NEWDB PIPELINING SASLv2 SCANF
STARTTLS USERDB XDEBUG
若上面的 Compiled with 有出現 MILTER 即代表了您的 sendmail 巳支援 Milter, 那是最好不過的了,讓您少掉了不少
預備工作,
1.2 我的 sendmail 目前不支援 Milter
此時建議您依自己的情況找一個支援 Milter 的 RPM 或是以 Source RPM 自己重做 RPM (rpmbuild),另外您也可以選擇
以 tarball 的方式做, tarball 的方式做會複雜許多,建議您多參考 Sendmail Compiling 一節說明
http://www.sendmail.org/tips/compiling.html
以我個人的例子來做介紹
代碼:
$>cd sendmail-8.13.7
# 以下您也可以自己用 editor 編輯,若不了解請多參考上述 compiling link 的說明,篇幅所限(其實是我想偷懶),無法
# 一一說明
$>cat <devtools/Site/site.config.m4
dnl # 可以在 cf 檔中使用 regexp
APPENDDEF(`confMAPDEF',`-DMAP_REGEX')
dnl # BDB , 這個是一定要的
APPENDDEF(`confENVDEF',`-DNEWDB')
dnl # MILTER 支援
APPENDDEF(`conf_sendmail_ENVDEF', `-DMILTER')
dnl # MILTER 不以 root 啟動
APPENDDEF(`conf_libmilter_ENVDEF', `-D_FFR_MILTER_ROOT_UNSAFE')
dnl # DNS 的一些函數
APPENDDEF(`confENVDEF',`-DDNSMAP')
dnl # MILTER,這個可以不用,但個人習慣除了 sendmail_ENVDEF 外,還會再加一次 ENVDEF
APPENDDEF(`confENVDEF',`-DMILTER')
dnl # STARTTLS, SMTPS 的東西
APPENDDEF(`confENVDEF',`-DSTARTTLS')
APPENDDEF(`conf_sendmail_ENVDEF', `-DSTARTTLS')
dnl # Complier 時所需的一些 include/lib 相關位置
APPENDDEF(`conf_sendmail_LIBS', `-lssl -lcrypto')
APPENDDEF(`confLIBDIRS',`-L/usr/local/ssl/lib -L/usr/lib -L/usr/local/lib')
APPENDDEF(`confINCDIRS',`-L/usr/local/ssl/include -I/usr/include/sasl')
APPENDDEF(`confINCDIRS',` -I/usr/include -I/usr/local/include')
APPENDDEF(`confLIBS',`-lsasl2 -lcrypt -lssl -lcrypto -lmilter')
dnl # SASL , SMTP AUTH 的東西
APPENDDEF(`confENVDEF',`-DSASL2')
define(`confAUTH_OPTIONS',`p')
dnl # TCP WRAPPER , 以便可以使用 /etc/hosts.{allow,deny} 的一些功能
APPENDDEF(`confENVNEF',`-DTCPWRAPPERS')
APPENDDEF(`conf_sendmail_LIBS', `-lwrap')
EOF
$>sh Build -c
#這裏會進行 Compiling,理論上不會有什麼 Error , 如果有 Error 需視狀況處理
$>service sendmail stop
$>service sendmail stop
$>service sendmail stop
$>killall -9 sendmail
$>sh Build install
# 下面路徑 sendmail-cf 視您的環境而定,主要是看您的 sendmail.mc 中的 include 位置為何
$>cp -Rf cf/* /usr/share/sendmail-cf
$>cd /etc/mail
# 直接使用原來的 sendmail.mc 即可
$>m4 sendmail.mc > sendmail.cf
$>service sendmail start
# 檢查 sendmail Compiling 的項目,是否出現 MILTER
$>sendmail -d0
以上只是做 sendmail 的昇級,安裝,支援 Milter, 重新啟動等等動作,目的是要讓您的 sendmail 可以加載其他的 Mail Filter,
如果您的 sendmail 巳經支援 MILTER 那重做 SENDMAIL 是不需要的,不過 dk-filter 要求 sendmail 最低版本需 8.13.X,
所以若您不是使用 8.13.X ,您必需找 rpm 來裝或是自己用 tarball 來裝(用 Source RPM 也很簡單的),如果您的 Sendmail 巳是
8.13.X 且支援 MILTER,那第一節部份您是可以不用管的.
2. 安裝 Domain Key Filter (dk-filter)
2.1 下載與安裝
project 網址為 https://sourceforge.net/projects/dk-milter/ , 撰寫本文時版本為 0.5.1,因為 DKIM 的標準尚
在討論中,但基本鶵形巳經有共識,相信未來只是 wording 的工作,但是內容並不會有太大的改變
(註:我用 0.5.1 無法通過 Yahoo 的 DKIM 認證, 0.4.1 是最多人用的)
代碼:
$>wget http://superb-west.dl.sourceforge.net/sourceforge/dkim-milter/dkim-milter-0.4.1.tar.gz
$>tar -zxvf dkim-milter-0.4.1.tar.gz
$>cd dkim-milter-0.4.1
$>sh Build -c
# 如果 compiling 時有 SSL 相關的函數出錯,請修改 dk-filter/Makefile.m4 中的
# APPENDDEF(`confINCDIRS', `-I/usr/local/ssl/include ')
# APPENDDEF(`confLIBDIRS', `-L/usr/local/ssl/lib ')
# 到對應的路徑
$>sh Build install
2.2 了解 dk-filter 參數的涵意
代碼:
$>dk-filter -h
-a peerlist file containing list of hosts to ignore # 那些 host 不做 DKIM check
-A auto-restart # dk-filter 死掉時自動重啟
-b modes select operating modes # s (singer) / v (verify) 預設為 sv
-c canon canonicalization to use when signing # 預設是 simple (表頭不改變),
# 另外為 relaxed (表頭可能修正,去除空白,不換行等等)
-C config configuration info (see man page) # 設定檔,詳見下述
-d domlist domains to sign # 要 sign 的 domain 列表,以逗號區隔
-D also sign subdomains # 一併 sign -d 之下 domain 的 sub-domain
-f don't fork-and-exit # 前景執行
-h append identifying header # 會在 Mail Header 中加入 X-DomainKeys 資訊
-H sign with explicit header lists # DomainKey-Signature 中說明 sign 的 header 資訊
-i ilist file containing list of internal (signing) hosts # 只做 sign, 不做 verify,預設為 127.0.0.1
-I elist file containing list of external domain clients # 透過此主機轉信之來源做 sign,不做 verify
-l log activity to system log # log 必要訊息到 maillog
-m mtalist MTA daemon names for which to sign # MTA 名字,也就是 DaemonPortOptions 中的 Name,預設是全部
-M macrolist MTA macros which enable signing # 不詳,沒用過
-o hdrlist list of headers to omit from signing # 那些 Header 不 sign,Ex: -o to,subject,date , From 一定要 sign
-P pidfile file to which to write pid # pid file 路徑
-s keyfile location of secret key file # private key
-S selector selector to use when signing # selector,會以 selector._domainkey.Domain 進行 type=TXT 查詢
-u userid change to specified userid # 以什麼身份執行
-V print version number and terminate # 版本資訊
上述參數的 hosts 格式可以是 IP,Domain 例如:
代碼:
# hosts format for dk-filter
1.2.3.4
100.100/16
eai1.twnic.tw
.twnic.net.tw
上述參數 -C config 檔中的設定方法,
代碼:
#result=action,result=action,...,括號內為簡寫
#Results:
# 依序為認證失敗,DNS 錯誤,Milter 內部錯誤,沒有 DKIM 欄位,沒有簽章欄位(b=)
badsignature(bad)
dnserror(dns)
internal(int)
nosignature(no)
signature-missing(miss)
#action:
# 依序為 同意,丟棄,臨時失敗,拒絕
accept(a)
discard(d)
tempfail(t)
reject(r)
所以若要拒絕沒有 DKIM 的信件,對於內部錯誤回應臨時失敗,拒絕認證失敗的信件即為 -C bad=r,no=r,int=t
2.3 建立 dk-filter running script
建立 /etc/sysconfig/dk-filter 檔
代碼:
#!/bin/bash
#以下請自行調整,主要為對應啟動時的參數
SOCKET="inet:8891@localhost"
CANON="simple"
DOMAIN=$(hostname)
PRIVATE_KEY="/etc/mail/abelyang.private"
USER=smmsp
HEADER_IGNORE="subject,date,message-id,to"
SELECTOR=$(date +%Y)
FILTER_RULE="bad=r,dns=r,int=r,no=a,miss=r"
建立 /etc/rc.d/init.d/dk-filter 啟動程式
(這裏有點隨便寫,能夠 start/stop 而以,但不能對應到 chkconfig 使用 =.=)
代碼:
#!/bin/bash
RETVAL=0
prog="dk-filter"
if [ -x /usr/bin/$prog ] ; then
PROGDIR=/usr/bin
elif [ -x /usr/local/bin/$prog ] ; then
PROGDIR=/usr/local/bin
else
exit 0
fi
SOCKET="inet:8891@localhost"
# Source configuration
if [ -f /etc/sysconfig/$prog ] ; then
. /etc/sysconfig/$prog
fi
start() {
ulimit -s 2048
$PROGDIR/$prog -H -h -l -P /var/run/dk-filter.pid \
$([ -n "$FILTER_RULE" ] && echo "-C $FILTER_RULE") \
$([ -n "$DOMAIN" ] && echo "-d $DOMAIN") \
$([ -n "$SELECTOR" ] && echo "-S $SELECTOR") \
$([ -n "$PRIVATE_KEY" ] && echo "-s $PRIVATE_KEY") \
$([ -n "$CANON" ] && echo "-c $CANON") \
$([ -n "$USER" ] && echo "-u $USER") \
$([ -n "$HEADER_IGNORE" ] && echo "-o $HEADER_IGNORE") \
-p $SOCKET
echo $cmd
echo
# Start daemon
echo "Starting $prog: [OK]"
[ -e $SOCKET ] && rm -f $SOCKET
return $RETVAL
}
stop() {
# Stop daemon
echo -n "Shutting down $prog: [OK]"
killall -9 $prog
RETVAL=$?
echo
[ -e $SOCKET ] && rm -f $SOCKET
# Stop daemon
echo -n "Shutting down $prog: "
killproc $prog
echo
[ -e $MX_SOCKET ] && rm -f $MX_SOCKET
}
# See how we were called.
case "$1" in
start)
start
;;
stop)
stop $2
;;
restart)
stop
start
RETVAL=$?
;;
*)
echo "Usage: $0 {start|stop|restart}"
exit 1
esac
exit $RETVAL
以上都只是軟體的準備動作,接下來我們要做的就是實際的簽章部份了
3. 設定 DKIM 的 private/public key 及建立 DNS 資訊
DKIM 的 key 使用 rsa 加密,不需要經過 CA 認證,所以 key 值都是由自己建立的,而一般會建議 key 長度小於 1024,主要
是因為最後要把 public key 放到 DNS 資訊記錄中,若 key 太長會造成 DNS 封包放不下,容易發生一些副作用,所以這是做
key 時要注意的地方 (一般 DNS query 稱為 basic query, udp 最大只能 512 bytes, 若要超過 512 bytes, 則 DNS query
需轉為 53/TCP,並設立模式為 truncate , 或是使用 EDNS0,讓 DNS 的回應可以大於 512 個 bytes)
3.1 手動產生 key
手動建立 key:
代碼:
#private key
$>openssl genrsa -out rsa.private 1024
Generating RSA private key, 1024 bit long modulus
..................++++++
..................................................................++++++
e is 65537 (0x10001)
#publick key
$>openssl rsa -in rsa.private -out rsa.public -pubout -outform PEM
writing RSA key
#以上即可建立完成
安裝 dk-filter 時,裏面附了一個 gentxt.csh (在 dk-filter 目錄裏),可以直接使用它來產生 key 及 DNS Record 內容
代碼:
$>./gentxt.csh 2006 eai1.twnic.tw
2006._domainkey IN TXT "g=; k=rsa; t=y; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDH/mYXWTmnFBrqjU8SQIJCXz+iO4H5JPRrg8zwmlKV0mgYpPCRthUVGa0hGyi6D+hNqvskd+0rCoLtpztoGexDRKnc OOd6VBy5OzKwupLXEoDa8tTc1g2CvdxVnt2r5Q8/3rbdf/3Uw17TugxdAidJD2Fb QIPo3hCbZ0izGE9OEQIDAQAB" ; ----- DomainKey 2006 for eai1.twnic.tw
# g= 表示 local-part (username 為任意,如果有 i= 時,要對應這個 g= 為 i= 的 local-part, 好像有看沒有懂,主要
# 是因為參數太多了,建議若有心人可以多看看 DKIM 的文件才能懂)
# k=rsa 表示 key 的演算法,這裏為固定用法
# t=y 表示測試 (其他參數講了只會讓大家困擾,怒我就不寫了,請參考 DKIM Draft)
此時 gentxt.csh 會在目錄下建立 2006.private 及 2006.public,而輸出的是你要放在 DNS 中的資料,所以需要在 DNS 建
立這個 DomainKey 的資料
代碼:
#named.conf
zone "twnic.tw" { type master;file "twnic";};
# file "twnic"
$TTL 3600
@ IN SOA ...略
; 其他 RR 略
$ORIGIN _domainkey.eai1.twnic.tw.
IN TXT "g=; k=rsa; t=y; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDH/mYXWTmnFBrqjU8SQIJCXz+iO4H5JPRrg8zwmlKV0mgYpPCRthUVGa0hGyi6D+hNqvskd+0rCoLtpztoGexDRKnc OOd6VBy5OzKwupLXEoDa8tTc1g2CvdxVnt2r5Q8/3rbdf/3Uw17TugxdAidJD2Fb QIPo3hCbZ0izGE9OEQIDAQAB" ; ----- DomainKey 2006 for eai1.twnic.tw
2006 IN TXT "g=; k=rsa; t=y; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDH/mYXWTmnFBrqjU8SQIJCXz+iO4H5JPRrg8zwmlKV0mgYpPCRthUVGa0hGyi6D+hNqvskd+0rCoLtpztoGexDRKnc OOd6VBy5OzKwupLXEoDa8tTc1g2CvdxVnt2r5Q8/3rbdf/3Uw17TugxdAidJD2Fb QIPo3hCbZ0izGE9OEQIDAQAB" ; ----- DomainKey 2006 for eai1.twnic.tw
2007 IN TXT "g=; k=rsa; t=y; p=AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" ; 2007
2006,2007 是 Selector,是指在做 DKIM DNS query 時要前置的名稱,用什麼名稱都可以,我的用意是在表示 2006 年我用這個
key, 2007 年我另一個 key,這裏面並沒有什麼強制規定,只要你的 Mail Header ,DKIM中標示 s=XXXX,d=DOMAIN , 那收信對
方就會看這個 s=XXXX 做 XXXX._domainkey.DOMAIN 的 type=TXT 查詢,如以本例即為
代碼:
# 查詢 2006._domainkey.eai1.twnic.tw 的 TXT Record
[root@eai1 dk-filter]# dig 2006._domainkey.eai1.twnic.tw txt
; <<>> DiG 9.3.0 <<>> 2006._domainkey.eai1.twnic.tw txt
;; global options: printcmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 52003
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 1, ADDITIONAL: 1
;; QUESTION SECTION:
;2006._domainkey.eai1.twnic.tw. IN TXT
;; ANSWER SECTION:
2006._domainkey.eai1.twnic.tw. 60 IN TXT "g=\; k=rsa\; t=y\; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDu1KF+c7ucCeilrmo1FH1nDEpt7DT4J4y71iGgKtpGfOo3/dEtLyw5t75VUKKwkAmmvUBVZACciqj/aZoujVXKnSSK4DDhbpLcRA3wABczUNCXe12izP6brTDxrfkg1yi+b+rwsqyAWkiMR32f6/9i/5o9chRl3uWyDoMIWHqY6QIDAQAB"
;; AUTHORITY SECTION:
twnic.tw. 86400 IN NS twnic.net.tw.
;; ADDITIONAL SECTION:
twnic.net.tw. 86400 IN A 211.72.210.250
;; Query time: 3 msec
;; SERVER: 211.72.210.250#53(211.72.210.250)
;; WHEN: Thu Jul 20 10:39:16 2006
;; MSG SIZE rcvd: 334
所以不論您以手動建立 KEY,並存入 DNS Record 中 (如上例),或使用 dk-filter 附的 gentxt.csh 產生 key 並抄至
DNS 中,其實都是一樣的,而後記得將 private key 保存好 (通常我都放到 /etc/mail 中),我用年區分主要用意在於強
迫自己每年要換一次 KEY
以上,我們做了 Sendmail MILTER 支援與否的確認,並且安裝了 dk-filter,產生了 private/public key,並建立了
對應的 DNS 資料,這些動作都是分開的,您那一個先做後做都沒有關係,上述的說明您可依章節獨立來看也可以,因為
我們尚未為 sendmail 和 dk-filter 建立溝通方式(socket),所以是沒有關係的
4. 修改 sendmail.mc 及測試
4.1 修改 sendmail.mc
要讓 Sendmail 能加入 DKIM 檢查需在 sendmail.mc 中加入必要資訊
代碼:
#在 sendmail.mc 的 Mailer 之前加入
dnl # 前略
dnl # 讓 MILTER 的 log 能出到最詳細資料,初學時要注意,資訊多一點有利於您的判讀,若熟悉了可以拿掉或調回到4以下
define(`confMILTER_LOG_LEVEL',`99')
dnl # 讓 Sendmail Log 到 15 以上,可以看見詳細的郵件溝通過程,但 maillog 會長很快
define(`confLOG_LEVEL',`15')
dnl # 加入 dk-filter ,進行 DKIM 的 sign/verify 動作 (mode=s,v,sv)
INPUT_MAIL_FILTER(`dkim-filter', `S=inet:8891@localhost')
dnl # 後略
4.2 啟動 dk-filter 及 sendmail
做好修改 sendmail.mc 動作好重新產生 sendmail.cf,並先確認 dk-filter 巳執行中,重新啟動 sendmail,
(切記, dk-filter 要先執行,才跑 sendmail,而後 dk-filter 有重啟都沒有關係)
代碼:
$>m4 sendmail.mc > sendmail.cf
$>/etc/rc.d/init.d/dk-filter start
$>(確認 dk-filter 巳執行中)
$>service sendmail restart
如此即完成了 sendmail DKIM 的功能,而初步完成後建議您先進行測試,以了解 sign 的功能是否正常
4.3 發信測試,Local Mail
試發一封寄給自己的信,確認其內容是否有 DKIM 訊息
代碼:
$>echo "" | mail abelyang -s "DKIM testing"
$>mail -u abelyang
看到的信件內容
From root@eai1.twnic.tw Thu Jul 20 11:16:05 2006
X-Spam-Checker-Version: SpamAssassin 3.1.3 (2006-06-01) on eai1.twnic.tw
X-Spam-Level:
X-Spam-Status: No, score=0.0 required=5.0 tests=DK_POLICY_SIGNSOME,
DK_POLICY_TESTING,DK_SIGNED,SPF_HELO_PASS,SPF_PASS autolearn=failed
version=3.1.3
X-DomainKeys: Sendmail DomainKeys Filter v0.4.1 eai1.twnic.tw k6K3G5FJ011141
DomainKey-Signature: a=rsa-sha1; s=2006; d=eai1.twnic.tw; c=simple; q=dns;
h=received:from;
b=rt7TfR5smobv7WnmQjddlRYWUNKCoIVwbUQZ9nek0xMOFlRqbXWMU9Es65ljpN1Yz
gMk9izKfxbMCkE8YE4BDmEczrWJ7bLKAHkXBS5gulx/l3t+cNBiP3KbQtAJ8LjJVTCe
kMEmp8+FVUkobhVVTxlJya9AkgEN2Cdnsc1WYhg=
Date: Thu, 20 Jul 2006 11:16:05 +0800
From: root
To: abelyang@eai1.twnic.tw
Subject: DKIM testing
看起來無誤,這其中的 X- 分別是 spamassassin 及 dk-filter 所加的,而個人測試主機之 spamassassin 有啟動 DKIM 及 SPF 的檢
查,所以 X-Spam-Status 中會有相關的資訊,但這個不是個人的重點
重點是這個 Header
代碼:
DomainKey-Signature: a=rsa-sha1; s=2006; d=eai1.twnic.tw; c=simple; q=dns;
h=received:from;
b=rt7TfR5smobv7WnmQjddlRYWUNKCoIVwbUQZ9nek0xMOFlRqbXWMU9Es65ljpN1Yz
gMk9izKfxbMCkE8YE4BDmEczrWJ7bLKAHkXBS5gulx/l3t+cNBiP3KbQtAJ8LjJVTCe
kMEmp8+FVUkobhVVTxlJya9AkgEN2Cdnsc1WYhg=
a= 表示加密方式
s= 為 selector
d= 為 Domain
c= 為 canon 方式,預設為 simple
q= 為 query 方式,目前只有 dns
h= 為以那些 Header 做簽證動作,因為我去掉了 (-o) 一些,所以 h= 那些
b= 簽證後的值,這個值為 base64
因為是自己發給自己(127.0.0.1),所以不會有 verify 的動作,我們現在用 telnet 來測試一下
代碼:
[root@eai1 dk-filter]# telnet eai1.twnic.tw 25
Trying 211.72.210.249...
Connected to eai1.twnic.tw.
Escape character is '^]'.
220 eai1.twnic.tw ESMTP Sendmail 8.13.6/8.13.6; Thu, 20 Jul 2006 11:24:38 +0800
ehlo eai1.twnic.tw
250-eai1.twnic.tw Hello eai1.twnic.tw [211.72.210.249], pleased to meet you
250-ENHANCEDSTATUSCODES
250-PIPELINING
250-8BITMIME
250-SIZE
250-DSN
250-ETRN
250-AUTH CRAM-MD5 LOGIN PLAIN
250-DELIVERBY
250 HELP
mail from:
250 2.1.0... Sender ok
rcpt to:
250 2.1.5... Recipient ok
data
354 Enter mail, end with "." on a line by itself
Date: Thu, 20 Jul 2006 11:16:05 +0800
From: root
To: abelyang@eai1.twnic.tw
Subject: DKIM testing
.
554 5.7.1 Command rejected
因為此時我們用的 IP 為 211.72.210.249,所以對於來信沒有 DKIM (nosig), 我們設定了 no=r, 所以信件就不收,即會
出現這樣的訊息. 依 DKIM 的 Draft 的願景,首重先推廣 DKIM,待 DKIM 有一定程度的普及後才會到 reject 的可能,但
我的用意在做說明,所以本文用的是沒有 sign 就 reject, 當然您可以不用 -C 參數,就不會有這樣的情況發生了
4.4 發信測試,外部
Yahoo 的 mail 目前有 DKIM,所以是我們最佳的測試目標,我們可以試發 Mail 到 yahoo.com.tw 上的帳號上進行測試,這
個測試主要在於了解自己的 DKIM 是否設定正確
yahoo mail 結果
由以上可知,這樣的過程是 OK 的, Yahoo 對我的來信進行了 Verify, 並且確認了這個信件是來自於我的 Domain,
若反向而為,從 Yahoo 向我的 Mail Server 發信,可以發信,但是 Yahoo 的 mail 發向我的信會有問題,這個問題在 maillog
會出現:
代碼:
Jul 21 16:52:25 eai1 sendmail[15482]: k6L8qPC4015482: milter_read(dkim-filter): cmd read returned 0, expecting 5
Jul 21 16:52:25 eai1 sendmail[15482]: k6L8qPC4015482: Milter (dkim-filter): to error state
這是 dk-filter 目前的 bug, 至預計下一版才會進行修正,不過目前巳有 0.5.1 版且此版本較能 follow DKIM draft, 但顯然
Yahoo 的 DKIM 只能配合到原來的 Draft-03 (意即 dkim 0.4.1 版),所以本處的介紹即以 0.4.1 版為主,而 0.5.1 版的使用
僅是大同小異(參數略有不同),而我們在使用 DKIM 發信給 Yahoo 時,使用 0.4.1 版 Yahoo 能夠正確的辨認我們的 Key 對不
對,而使用 0.5.1 因為一些欄位 Yahoo 看不懂,所以它就會認為我們送的信沒有 key (nosig),反而造成它無法認為我們使用
DKIM.
5. 結語
即使 DKIM 立意雖不錯,但是仍不能預防 SPAM,因為 SPAMER 可以 follow 標準(Draft),而 verify 一樣會 pass,所以個人並不
期待它能有多大的效果,但是 DKIM 對於信確實由這個網域名稱所發出的檢查是能正確驗證的,而對於我所使用的 DKIM 所發出來
的信件,它仍歸類為垃圾郵件 (我有反解,且正反解一致,也有 DKIM),所以可以知道的是它不是僅以反解或 DKIM 來判斷
一封郵件是否為 Spam,也和郵件內容的長短無關,而可能是其他因素所致.
參考:
1. http://www.atmarkit.co.jp/fsecurity/special/88domainkeys/dk04.html
2. http://www.erikberg.com/notes/milters.html
3. http://www.elandsys.com/resources/sendmail/dkim.html
附錄1, dk-filter 0.4.1 Header,DKIM Draft 02 版 Mail Header
代碼:
DomainKey-Signature:a=rsa-sha1; s=2006; d=eai1.twnic.tw; c=simple; q=dns;
h=received:from;
b=YM3a3E8rF5sQy+0Mb8K0G7bkQ8Nq3gPEfoY8nZtk9TOlHsiyFEYPtQbMXi50Eo9Wd
TJ2Fa61BHNsUrm6PYH9En8MaRF1zI3HgLms6GELpChbF2bYjrAXqu9hhjWpxzUDZoI2
DlG6rPSiC39bviTqDUDuCpAY+Ssw6LuNp6FyY5Q=
附錄2, dkim-filter 0.5.1 Header , DKIM Draft 03 版 Mail Header
代碼:
DKIM-Signature: a=rsa-sha1; c=relaxed/simple; d=eai1.twnic.tw; s=2006; t=1153707289; bh=sN3ES5nmlXy4I3QtCSbftYMZfrY=;
h=Received:Date:From:Message-Id:To:Subject;
b=kyZaJUnHKfUX0IyzjDRpvz/FrT0XQXLt08WhGf/s5L
gSFqlrAgJAQ5jb5gsIqhLBLW5HZBJbGSf87RdUilKE8BvuphrERJikgYbPthuieK6ce
oxlC9JGGrb9joKnZ/X3HYTLo1iUyveC6QsAQ4T1zGcnkPK8dTJ95hXeXnK87ZM=
# t= 表示 sign 的時間,而 bh= 表示 Body 的 sign 結果,c= 也進行了一些調整
Sendmail Domain Key 教學
歡迎轉載 ,但不得作為商業用途
作者: abelyang
最後修正時間: 2006/07/24 00:10
轉載時請保持此一宣告
Sendmail + DomainKey 實作分享
前言
Domain Key (DKIM) 目前尚無標準(RFC) 文件,目前 IETF Draft 只到 04 版(最終到 -06),估計還要一年多才會形成 RFC,
相關訊息可參考 IETF DKIM Working Group (http://www.ietf.org/html.charters/dkim-charter.html), 及
Domain Key 網站 ( http://mipassoc.org/dkim/ ), 這個網站可以找到各種 MTA 如何 support DKIM 的文件及 Source
Domain Key 主要是由 Yahoo 所推的網域名稱和郵件伺服器間認證方式, Server 所發出來的信件使用 private key
加密必要的表頭(Ex: From:Subject:Date),目的 MTA 在收到信件時取出這些表頭,以 public key (從 DNS 中取出,
後述)進行表頭驗證,從驗證的結果中得到一個 return 值,並針對這些值由目的 MTA 決定動作 (Accept/Reject/Discare..),
所以, MTA 要支援 Domain Key, 不同的 MTA 做法稍有不同,僅以個人較熟悉之 sendmail 進行介紹,以供大家參考.
(據聞 postfix 也支援 Milter , 但個人未用過 postfix,故留待有緣人自己研究了,或上述專門介紹 DKIM 的網站中,
也有各種 MTA 的做法).
最後,值得一提的是, Yahoo 目前使用的 DKIM 版本是 02 版,而目前最新的 Draft 到 04 版,最近的 DKIM Milter 則支援
0.3 版,所以,我們的介紹是配合 Yahoo 使用 DKIM 能支援 02 版的 dk-filter 0.4.1
1. sendmail 準備工作
1.1 sendmail 需支援 Milter
不論 DKIM 也好, SPF 也罷,在 Sendmail 中實現都是以 Milter (Mail Fitler) 來做, Milter 的功能是在 SMTP 協商
的過程式去連接一個外部程式進行檢驗,例如 ehlo/mail from/rcpt to/data 等,每個步驟的過程都可以連接一個外部程
式進行檢驗及行為處理,所以,若 user 有需要可以修改 Envelpe To, Header 等,而 DKIM 的 filter 主要的工作是進行
加 Header 及取 Header 驗證的工作,故只有在 Data 上做文章. 所以您的 sendmail 有沒有支援 Milter 決定了你可否
直接使用 DKIM filter (dk-filter),或是必需重新安裝 sendmail
代碼:
# 檢驗 sendmail 是否支援 Milter (-d0 表示要看 Complier 參數,不同的 -dX.Y 各有不同意義)
[root@eai1 mail]# sendmail -d0 Version 8.13.7
Compiled with: DNSMAP LOG MAP_REGEX MATCHGECOS MILTER MIME7TO8 MIME8TO7
NAMED_BIND NETINET NETUNIX NEWDB PIPELINING SASLv2 SCANF
STARTTLS USERDB XDEBUG
若上面的 Compiled with 有出現 MILTER 即代表了您的 sendmail 巳支援 Milter, 那是最好不過的了,讓您少掉了不少
預備工作,
1.2 我的 sendmail 目前不支援 Milter
此時建議您依自己的情況找一個支援 Milter 的 RPM 或是以 Source RPM 自己重做 RPM (rpmbuild),另外您也可以選擇
以 tarball 的方式做, tarball 的方式做會複雜許多,建議您多參考 Sendmail Compiling 一節說明
http://www.sendmail.org/tips/compiling.html
以我個人的例子來做介紹
代碼:
$>cd sendmail-8.13.7
# 以下您也可以自己用 editor 編輯,若不了解請多參考上述 compiling link 的說明,篇幅所限(其實是我想偷懶),無法
# 一一說明
$>cat <
dnl # 可以在 cf 檔中使用 regexp
APPENDDEF(`confMAPDEF',`-DMAP_REGEX')
dnl # BDB , 這個是一定要的
APPENDDEF(`confENVDEF',`-DNEWDB')
dnl # MILTER 支援
APPENDDEF(`conf_sendmail_ENVDEF', `-DMILTER')
dnl # MILTER 不以 root 啟動
APPENDDEF(`conf_libmilter_ENVDEF', `-D_FFR_MILTER_ROOT_UNSAFE')
dnl # DNS 的一些函數
APPENDDEF(`confENVDEF',`-DDNSMAP')
dnl # MILTER,這個可以不用,但個人習慣除了 sendmail_ENVDEF 外,還會再加一次 ENVDEF
APPENDDEF(`confENVDEF',`-DMILTER')
dnl # STARTTLS, SMTPS 的東西
APPENDDEF(`confENVDEF',`-DSTARTTLS')
APPENDDEF(`conf_sendmail_ENVDEF', `-DSTARTTLS')
dnl # Complier 時所需的一些 include/lib 相關位置
APPENDDEF(`conf_sendmail_LIBS', `-lssl -lcrypto')
APPENDDEF(`confLIBDIRS',`-L/usr/local/ssl/lib -L/usr/lib -L/usr/local/lib')
APPENDDEF(`confINCDIRS',`-L/usr/local/ssl/include -I/usr/include/sasl')
APPENDDEF(`confINCDIRS',` -I/usr/include -I/usr/local/include')
APPENDDEF(`confLIBS',`-lsasl2 -lcrypt -lssl -lcrypto -lmilter')
dnl # SASL , SMTP AUTH 的東西
APPENDDEF(`confENVDEF',`-DSASL2')
define(`confAUTH_OPTIONS',`p')
dnl # TCP WRAPPER , 以便可以使用 /etc/hosts.{allow,deny} 的一些功能
APPENDDEF(`confENVNEF',`-DTCPWRAPPERS')
APPENDDEF(`conf_sendmail_LIBS', `-lwrap')
EOF
$>sh Build -c
#這裏會進行 Compiling,理論上不會有什麼 Error , 如果有 Error 需視狀況處理
$>service sendmail stop
$>service sendmail stop
$>service sendmail stop
$>killall -9 sendmail
$>sh Build install
# 下面路徑 sendmail-cf 視您的環境而定,主要是看您的 sendmail.mc 中的 include 位置為何
$>cp -Rf cf/* /usr/share/sendmail-cf
$>cd /etc/mail
# 直接使用原來的 sendmail.mc 即可
$>m4 sendmail.mc > sendmail.cf
$>service sendmail start
# 檢查 sendmail Compiling 的項目,是否出現 MILTER
$>sendmail -d0
以上只是做 sendmail 的昇級,安裝,支援 Milter, 重新啟動等等動作,目的是要讓您的 sendmail 可以加載其他的 Mail Filter,
如果您的 sendmail 巳經支援 MILTER 那重做 SENDMAIL 是不需要的,不過 dk-filter 要求 sendmail 最低版本需 8.13.X,
所以若您不是使用 8.13.X ,您必需找 rpm 來裝或是自己用 tarball 來裝(用 Source RPM 也很簡單的),如果您的 Sendmail 巳是
8.13.X 且支援 MILTER,那第一節部份您是可以不用管的.
2. 安裝 Domain Key Filter (dk-filter)
2.1 下載與安裝
project 網址為 https://sourceforge.net/projects/dk-milter/ , 撰寫本文時版本為 0.5.1,因為 DKIM 的標準尚
在討論中,但基本鶵形巳經有共識,相信未來只是 wording 的工作,但是內容並不會有太大的改變
(註:我用 0.5.1 無法通過 Yahoo 的 DKIM 認證, 0.4.1 是最多人用的)
代碼:
$>wget http://superb-west.dl.sourceforge.net/sourceforge/dkim-milter/dkim-milter-0.4.1.tar.gz
$>tar -zxvf dkim-milter-0.4.1.tar.gz
$>cd dkim-milter-0.4.1
$>sh Build -c
# 如果 compiling 時有 SSL 相關的函數出錯,請修改 dk-filter/Makefile.m4 中的
# APPENDDEF(`confINCDIRS', `-I/usr/local/ssl/include ')
# APPENDDEF(`confLIBDIRS', `-L/usr/local/ssl/lib ')
# 到對應的路徑
$>sh Build install
2.2 了解 dk-filter 參數的涵意
代碼:
$>dk-filter -h
-a peerlist file containing list of hosts to ignore # 那些 host 不做 DKIM check
-A auto-restart # dk-filter 死掉時自動重啟
-b modes select operating modes # s (singer) / v (verify) 預設為 sv
-c canon canonicalization to use when signing # 預設是 simple (表頭不改變),
# 另外為 relaxed (表頭可能修正,去除空白,不換行等等)
-C config configuration info (see man page) # 設定檔,詳見下述
-d domlist domains to sign # 要 sign 的 domain 列表,以逗號區隔
-D also sign subdomains # 一併 sign -d 之下 domain 的 sub-domain
-f don't fork-and-exit # 前景執行
-h append identifying header # 會在 Mail Header 中加入 X-DomainKeys 資訊
-H sign with explicit header lists # DomainKey-Signature 中說明 sign 的 header 資訊
-i ilist file containing list of internal (signing) hosts # 只做 sign, 不做 verify,預設為 127.0.0.1
-I elist file containing list of external domain clients # 透過此主機轉信之來源做 sign,不做 verify
-l log activity to system log # log 必要訊息到 maillog
-m mtalist MTA daemon names for which to sign # MTA 名字,也就是 DaemonPortOptions 中的 Name,預設是全部
-M macrolist MTA macros which enable signing # 不詳,沒用過
-o hdrlist list of headers to omit from signing # 那些 Header 不 sign,Ex: -o to,subject,date , From 一定要 sign
-P pidfile file to which to write pid # pid file 路徑
-s keyfile location of secret key file # private key
-S selector selector to use when signing # selector,會以 selector._domainkey.Domain 進行 type=TXT 查詢
-u userid change to specified userid # 以什麼身份執行
-V print version number and terminate # 版本資訊
上述參數的 hosts 格式可以是 IP,Domain 例如:
代碼:
# hosts format for dk-filter
1.2.3.4
100.100/16
eai1.twnic.tw
.twnic.net.tw
上述參數 -C config 檔中的設定方法,
代碼:
#result=action,result=action,...,括號內為簡寫
#Results:
# 依序為認證失敗,DNS 錯誤,Milter 內部錯誤,沒有 DKIM 欄位,沒有簽章欄位(b=)
badsignature(bad)
dnserror(dns)
internal(int)
nosignature(no)
signature-missing(miss)
#action:
# 依序為 同意,丟棄,臨時失敗,拒絕
accept(a)
discard(d)
tempfail(t)
reject(r)
所以若要拒絕沒有 DKIM 的信件,對於內部錯誤回應臨時失敗,拒絕認證失敗的信件即為 -C bad=r,no=r,int=t
2.3 建立 dk-filter running script
建立 /etc/sysconfig/dk-filter 檔
代碼:
#!/bin/bash
#以下請自行調整,主要為對應啟動時的參數
SOCKET="inet:8891@localhost"
CANON="simple"
DOMAIN=$(hostname)
PRIVATE_KEY="/etc/mail/abelyang.private"
USER=smmsp
HEADER_IGNORE="subject,date,message-id,to"
SELECTOR=$(date +%Y)
FILTER_RULE="bad=r,dns=r,int=r,no=a,miss=r"
建立 /etc/rc.d/init.d/dk-filter 啟動程式
(這裏有點隨便寫,能夠 start/stop 而以,但不能對應到 chkconfig 使用 =.=)
代碼:
#!/bin/bash
RETVAL=0
prog="dk-filter"
if [ -x /usr/bin/$prog ] ; then
PROGDIR=/usr/bin
elif [ -x /usr/local/bin/$prog ] ; then
PROGDIR=/usr/local/bin
else
exit 0
fi
SOCKET="inet:8891@localhost"
# Source configuration
if [ -f /etc/sysconfig/$prog ] ; then
. /etc/sysconfig/$prog
fi
start() {
ulimit -s 2048
$PROGDIR/$prog -H -h -l -P /var/run/dk-filter.pid \
$([ -n "$FILTER_RULE" ] && echo "-C $FILTER_RULE") \
$([ -n "$DOMAIN" ] && echo "-d $DOMAIN") \
$([ -n "$SELECTOR" ] && echo "-S $SELECTOR") \
$([ -n "$PRIVATE_KEY" ] && echo "-s $PRIVATE_KEY") \
$([ -n "$CANON" ] && echo "-c $CANON") \
$([ -n "$USER" ] && echo "-u $USER") \
$([ -n "$HEADER_IGNORE" ] && echo "-o $HEADER_IGNORE") \
-p $SOCKET
echo $cmd
echo
# Start daemon
echo "Starting $prog: [OK]"
[ -e $SOCKET ] && rm -f $SOCKET
return $RETVAL
}
stop() {
# Stop daemon
echo -n "Shutting down $prog: [OK]"
killall -9 $prog
RETVAL=$?
echo
[ -e $SOCKET ] && rm -f $SOCKET
# Stop daemon
echo -n "Shutting down $prog: "
killproc $prog
echo
[ -e $MX_SOCKET ] && rm -f $MX_SOCKET
}
# See how we were called.
case "$1" in
start)
start
;;
stop)
stop $2
;;
restart)
stop
start
RETVAL=$?
;;
*)
echo "Usage: $0 {start|stop|restart}"
exit 1
esac
exit $RETVAL
以上都只是軟體的準備動作,接下來我們要做的就是實際的簽章部份了
3. 設定 DKIM 的 private/public key 及建立 DNS 資訊
DKIM 的 key 使用 rsa 加密,不需要經過 CA 認證,所以 key 值都是由自己建立的,而一般會建議 key 長度小於 1024,主要
是因為最後要把 public key 放到 DNS 資訊記錄中,若 key 太長會造成 DNS 封包放不下,容易發生一些副作用,所以這是做
key 時要注意的地方 (一般 DNS query 稱為 basic query, udp 最大只能 512 bytes, 若要超過 512 bytes, 則 DNS query
需轉為 53/TCP,並設立模式為 truncate , 或是使用 EDNS0,讓 DNS 的回應可以大於 512 個 bytes)
3.1 手動產生 key
手動建立 key:
代碼:
#private key
$>openssl genrsa -out rsa.private 1024
Generating RSA private key, 1024 bit long modulus
..................++++++
..................................................................++++++
e is 65537 (0x10001)
#publick key
$>openssl rsa -in rsa.private -out rsa.public -pubout -outform PEM
writing RSA key
#以上即可建立完成
安裝 dk-filter 時,裏面附了一個 gentxt.csh (在 dk-filter 目錄裏),可以直接使用它來產生 key 及 DNS Record 內容
代碼:
$>./gentxt.csh 2006 eai1.twnic.tw
2006._domainkey IN TXT "g=; k=rsa; t=y; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDH/mYXWTmnFBrqjU8SQIJCXz+iO4H5JPRrg8zwmlKV0mgYpPCRthUVGa0hGyi6D+hNqvskd+0rCoLtpztoGexDRKnc OOd6VBy5OzKwupLXEoDa8tTc1g2CvdxVnt2r5Q8/3rbdf/3Uw17TugxdAidJD2Fb QIPo3hCbZ0izGE9OEQIDAQAB" ; ----- DomainKey 2006 for eai1.twnic.tw
# g= 表示 local-part (username 為任意,如果有 i= 時,要對應這個 g= 為 i= 的 local-part, 好像有看沒有懂,主要
# 是因為參數太多了,建議若有心人可以多看看 DKIM 的文件才能懂)
# k=rsa 表示 key 的演算法,這裏為固定用法
# t=y 表示測試 (其他參數講了只會讓大家困擾,怒我就不寫了,請參考 DKIM Draft)
此時 gentxt.csh 會在目錄下建立 2006.private 及 2006.public,而輸出的是你要放在 DNS 中的資料,所以需要在 DNS 建
立這個 DomainKey 的資料
代碼:
#named.conf
zone "twnic.tw" { type master;file "twnic";};
# file "twnic"
$TTL 3600
@ IN SOA ...略
; 其他 RR 略
$ORIGIN _domainkey.eai1.twnic.tw.
IN TXT "g=; k=rsa; t=y; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDH/mYXWTmnFBrqjU8SQIJCXz+iO4H5JPRrg8zwmlKV0mgYpPCRthUVGa0hGyi6D+hNqvskd+0rCoLtpztoGexDRKnc OOd6VBy5OzKwupLXEoDa8tTc1g2CvdxVnt2r5Q8/3rbdf/3Uw17TugxdAidJD2Fb QIPo3hCbZ0izGE9OEQIDAQAB" ; ----- DomainKey 2006 for eai1.twnic.tw
2006 IN TXT "g=; k=rsa; t=y; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDH/mYXWTmnFBrqjU8SQIJCXz+iO4H5JPRrg8zwmlKV0mgYpPCRthUVGa0hGyi6D+hNqvskd+0rCoLtpztoGexDRKnc OOd6VBy5OzKwupLXEoDa8tTc1g2CvdxVnt2r5Q8/3rbdf/3Uw17TugxdAidJD2Fb QIPo3hCbZ0izGE9OEQIDAQAB" ; ----- DomainKey 2006 for eai1.twnic.tw
2007 IN TXT "g=; k=rsa; t=y; p=AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" ; 2007
2006,2007 是 Selector,是指在做 DKIM DNS query 時要前置的名稱,用什麼名稱都可以,我的用意是在表示 2006 年我用這個
key, 2007 年我另一個 key,這裏面並沒有什麼強制規定,只要你的 Mail Header ,DKIM中標示 s=XXXX,d=DOMAIN , 那收信對
方就會看這個 s=XXXX 做 XXXX._domainkey.DOMAIN 的 type=TXT 查詢,如以本例即為
代碼:
# 查詢 2006._domainkey.eai1.twnic.tw 的 TXT Record
[root@eai1 dk-filter]# dig 2006._domainkey.eai1.twnic.tw txt
; <<>> DiG 9.3.0 <<>> 2006._domainkey.eai1.twnic.tw txt
;; global options: printcmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 52003
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 1, ADDITIONAL: 1
;; QUESTION SECTION:
;2006._domainkey.eai1.twnic.tw. IN TXT
;; ANSWER SECTION:
2006._domainkey.eai1.twnic.tw. 60 IN TXT "g=\; k=rsa\; t=y\; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDu1KF+c7ucCeilrmo1FH1nDEpt7DT4J4y71iGgKtpGfOo3/dEtLyw5t75VUKKwkAmmvUBVZACciqj/aZoujVXKnSSK4DDhbpLcRA3wABczUNCXe12izP6brTDxrfkg1yi+b+rwsqyAWkiMR32f6/9i/5o9chRl3uWyDoMIWHqY6QIDAQAB"
;; AUTHORITY SECTION:
twnic.tw. 86400 IN NS twnic.net.tw.
;; ADDITIONAL SECTION:
twnic.net.tw. 86400 IN A 211.72.210.250
;; Query time: 3 msec
;; SERVER: 211.72.210.250#53(211.72.210.250)
;; WHEN: Thu Jul 20 10:39:16 2006
;; MSG SIZE rcvd: 334
所以不論您以手動建立 KEY,並存入 DNS Record 中 (如上例),或使用 dk-filter 附的 gentxt.csh 產生 key 並抄至
DNS 中,其實都是一樣的,而後記得將 private key 保存好 (通常我都放到 /etc/mail 中),我用年區分主要用意在於強
迫自己每年要換一次 KEY
以上,我們做了 Sendmail MILTER 支援與否的確認,並且安裝了 dk-filter,產生了 private/public key,並建立了
對應的 DNS 資料,這些動作都是分開的,您那一個先做後做都沒有關係,上述的說明您可依章節獨立來看也可以,因為
我們尚未為 sendmail 和 dk-filter 建立溝通方式(socket),所以是沒有關係的
4. 修改 sendmail.mc 及測試
4.1 修改 sendmail.mc
要讓 Sendmail 能加入 DKIM 檢查需在 sendmail.mc 中加入必要資訊
代碼:
#在 sendmail.mc 的 Mailer 之前加入
dnl # 前略
dnl # 讓 MILTER 的 log 能出到最詳細資料,初學時要注意,資訊多一點有利於您的判讀,若熟悉了可以拿掉或調回到4以下
define(`confMILTER_LOG_LEVEL',`99')
dnl # 讓 Sendmail Log 到 15 以上,可以看見詳細的郵件溝通過程,但 maillog 會長很快
define(`confLOG_LEVEL',`15')
dnl # 加入 dk-filter ,進行 DKIM 的 sign/verify 動作 (mode=s,v,sv)
INPUT_MAIL_FILTER(`dkim-filter', `S=inet:8891@localhost')
dnl # 後略
4.2 啟動 dk-filter 及 sendmail
做好修改 sendmail.mc 動作好重新產生 sendmail.cf,並先確認 dk-filter 巳執行中,重新啟動 sendmail,
(切記, dk-filter 要先執行,才跑 sendmail,而後 dk-filter 有重啟都沒有關係)
代碼:
$>m4 sendmail.mc > sendmail.cf
$>/etc/rc.d/init.d/dk-filter start
$>(確認 dk-filter 巳執行中)
$>service sendmail restart
如此即完成了 sendmail DKIM 的功能,而初步完成後建議您先進行測試,以了解 sign 的功能是否正常
4.3 發信測試,Local Mail
試發一封寄給自己的信,確認其內容是否有 DKIM 訊息
代碼:
$>echo "" | mail abelyang -s "DKIM testing"
$>mail -u abelyang
看到的信件內容
From root@eai1.twnic.tw Thu Jul 20 11:16:05 2006
X-Spam-Checker-Version: SpamAssassin 3.1.3 (2006-06-01) on eai1.twnic.tw
X-Spam-Level:
X-Spam-Status: No, score=0.0 required=5.0 tests=DK_POLICY_SIGNSOME,
DK_POLICY_TESTING,DK_SIGNED,SPF_HELO_PASS,SPF_PASS autolearn=failed
version=3.1.3
X-DomainKeys: Sendmail DomainKeys Filter v0.4.1 eai1.twnic.tw k6K3G5FJ011141
DomainKey-Signature: a=rsa-sha1; s=2006; d=eai1.twnic.tw; c=simple; q=dns;
h=received:from;
b=rt7TfR5smobv7WnmQjddlRYWUNKCoIVwbUQZ9nek0xMOFlRqbXWMU9Es65ljpN1Yz
gMk9izKfxbMCkE8YE4BDmEczrWJ7bLKAHkXBS5gulx/l3t+cNBiP3KbQtAJ8LjJVTCe
kMEmp8+FVUkobhVVTxlJya9AkgEN2Cdnsc1WYhg=
Date: Thu, 20 Jul 2006 11:16:05 +0800
From: root
To: abelyang@eai1.twnic.tw
Subject: DKIM testing
看起來無誤,這其中的 X- 分別是 spamassassin 及 dk-filter 所加的,而個人測試主機之 spamassassin 有啟動 DKIM 及 SPF 的檢
查,所以 X-Spam-Status 中會有相關的資訊,但這個不是個人的重點
重點是這個 Header
代碼:
DomainKey-Signature: a=rsa-sha1; s=2006; d=eai1.twnic.tw; c=simple; q=dns;
h=received:from;
b=rt7TfR5smobv7WnmQjddlRYWUNKCoIVwbUQZ9nek0xMOFlRqbXWMU9Es65ljpN1Yz
gMk9izKfxbMCkE8YE4BDmEczrWJ7bLKAHkXBS5gulx/l3t+cNBiP3KbQtAJ8LjJVTCe
kMEmp8+FVUkobhVVTxlJya9AkgEN2Cdnsc1WYhg=
a= 表示加密方式
s= 為 selector
d= 為 Domain
c= 為 canon 方式,預設為 simple
q= 為 query 方式,目前只有 dns
h= 為以那些 Header 做簽證動作,因為我去掉了 (-o) 一些,所以 h= 那些
b= 簽證後的值,這個值為 base64
因為是自己發給自己(127.0.0.1),所以不會有 verify 的動作,我們現在用 telnet 來測試一下
代碼:
[root@eai1 dk-filter]# telnet eai1.twnic.tw 25
Trying 211.72.210.249...
Connected to eai1.twnic.tw.
Escape character is '^]'.
220 eai1.twnic.tw ESMTP Sendmail 8.13.6/8.13.6; Thu, 20 Jul 2006 11:24:38 +0800
ehlo eai1.twnic.tw
250-eai1.twnic.tw Hello eai1.twnic.tw [211.72.210.249], pleased to meet you
250-ENHANCEDSTATUSCODES
250-PIPELINING
250-8BITMIME
250-SIZE
250-DSN
250-ETRN
250-AUTH CRAM-MD5 LOGIN PLAIN
250-DELIVERBY
250 HELP
mail from:
250 2.1.0
rcpt to:
250 2.1.5
data
354 Enter mail, end with "." on a line by itself
Date: Thu, 20 Jul 2006 11:16:05 +0800
From: root
To: abelyang@eai1.twnic.tw
Subject: DKIM testing
.
554 5.7.1 Command rejected
因為此時我們用的 IP 為 211.72.210.249,所以對於來信沒有 DKIM (nosig), 我們設定了 no=r, 所以信件就不收,即會
出現這樣的訊息. 依 DKIM 的 Draft 的願景,首重先推廣 DKIM,待 DKIM 有一定程度的普及後才會到 reject 的可能,但
我的用意在做說明,所以本文用的是沒有 sign 就 reject, 當然您可以不用 -C 參數,就不會有這樣的情況發生了
4.4 發信測試,外部
Yahoo 的 mail 目前有 DKIM,所以是我們最佳的測試目標,我們可以試發 Mail 到 yahoo.com.tw 上的帳號上進行測試,這
個測試主要在於了解自己的 DKIM 是否設定正確
yahoo mail 結果
由以上可知,這樣的過程是 OK 的, Yahoo 對我的來信進行了 Verify, 並且確認了這個信件是來自於我的 Domain,
若反向而為,從 Yahoo 向我的 Mail Server 發信,可以發信,但是 Yahoo 的 mail 發向我的信會有問題,這個問題在 maillog
會出現:
代碼:
Jul 21 16:52:25 eai1 sendmail[15482]: k6L8qPC4015482: milter_read(dkim-filter): cmd read returned 0, expecting 5
Jul 21 16:52:25 eai1 sendmail[15482]: k6L8qPC4015482: Milter (dkim-filter): to error state
這是 dk-filter 目前的 bug, 至預計下一版才會進行修正,不過目前巳有 0.5.1 版且此版本較能 follow DKIM draft, 但顯然
Yahoo 的 DKIM 只能配合到原來的 Draft-03 (意即 dkim 0.4.1 版),所以本處的介紹即以 0.4.1 版為主,而 0.5.1 版的使用
僅是大同小異(參數略有不同),而我們在使用 DKIM 發信給 Yahoo 時,使用 0.4.1 版 Yahoo 能夠正確的辨認我們的 Key 對不
對,而使用 0.5.1 因為一些欄位 Yahoo 看不懂,所以它就會認為我們送的信沒有 key (nosig),反而造成它無法認為我們使用
DKIM.
5. 結語
即使 DKIM 立意雖不錯,但是仍不能預防 SPAM,因為 SPAMER 可以 follow 標準(Draft),而 verify 一樣會 pass,所以個人並不
期待它能有多大的效果,但是 DKIM 對於信確實由這個網域名稱所發出的檢查是能正確驗證的,而對於我所使用的 DKIM 所發出來
的信件,它仍歸類為垃圾郵件 (我有反解,且正反解一致,也有 DKIM),所以可以知道的是它不是僅以反解或 DKIM 來判斷
一封郵件是否為 Spam,也和郵件內容的長短無關,而可能是其他因素所致.
參考:
1. http://www.atmarkit.co.jp/fsecurity/special/88domainkeys/dk04.html
2. http://www.erikberg.com/notes/milters.html
3. http://www.elandsys.com/resources/sendmail/dkim.html
附錄1, dk-filter 0.4.1 Header,DKIM Draft 02 版 Mail Header
代碼:
DomainKey-Signature:a=rsa-sha1; s=2006; d=eai1.twnic.tw; c=simple; q=dns;
h=received:from;
b=YM3a3E8rF5sQy+0Mb8K0G7bkQ8Nq3gPEfoY8nZtk9TOlHsiyFEYPtQbMXi50Eo9Wd
TJ2Fa61BHNsUrm6PYH9En8MaRF1zI3HgLms6GELpChbF2bYjrAXqu9hhjWpxzUDZoI2
DlG6rPSiC39bviTqDUDuCpAY+Ssw6LuNp6FyY5Q=
附錄2, dkim-filter 0.5.1 Header , DKIM Draft 03 版 Mail Header
代碼:
DKIM-Signature: a=rsa-sha1; c=relaxed/simple; d=eai1.twnic.tw; s=2006; t=1153707289; bh=sN3ES5nmlXy4I3QtCSbftYMZfrY=;
h=Received:Date:From:Message-Id:To:Subject;
b=kyZaJUnHKfUX0IyzjDRpvz/FrT0XQXLt08WhGf/s5L
gSFqlrAgJAQ5jb5gsIqhLBLW5HZBJbGSf87RdUilKE8BvuphrERJikgYbPthuieK6ce
oxlC9JGGrb9joKnZ/X3HYTLo1iUyveC6QsAQ4T1zGcnkPK8dTJ95hXeXnK87ZM=
# t= 表示 sign 的時間,而 bh= 表示 Body 的 sign 結果,c= 也進行了一些調整
全站熱搜
留言列表