SMTP協定分析
第1章. SMTP概述
1.1. SMTP在郵件通信中的位置
SMTP,即簡單郵件傳送協定,所相應RFC文檔為RFC821。同http等多數應用層協定一樣,它工作在C/S模式下,用來實作網際網路上的郵件傳送。SMTP在整個電子郵件通信中所處的位置如圖 1所看到的。
圖 1電子郵件的通信過程
能夠看出,SMTP是用來将客戶機上的郵件傳送到server上。這裡的客戶機是指某次連接配接中的發送方,server是指對應的接收方。在解說發送郵件的整個通信過程前,先解釋一以下幾個術語。
1.2. 幾個術語
1.2.1. 郵件
郵件是一種消息的格式,由信封、首部和正文組成。
信封上最重要的是收信人的位址。郵件server用這個位址将郵件發送到收信人所在的郵件server上。
首部是由使用者代理或郵件server加入的一些資訊。包含Received、Message-ID、From、Data、Reply-To、X-Phone、X-Mailer、To和Subject等字段。
正文是是發送使用者發給接收使用者封包的内容。RFC 822 規定正文為NVT ASCII文字行。
更為具體的說明,請參考RFC821和RFC822等協定。
1.2.2. 使用者代理
使用者代理UA(User Agent)是使用者與電子郵件系統的互動接口,一般來說它就是我們PC機上的一個程式。Windows上常見的使用者代理是Foxmail和Outlook Express。
使用者代理提供一個好的使用者界面,它提取使用者在其界面填寫的各項資訊,生成一封符合SMTP等郵件标準的郵件,然後採用SMTP協定将郵件發送到發送端郵件server。
1.2.3. 郵件server
郵件server是電子郵件系統的核心,它用來發送和接收郵件。郵件server不同于普通PC的是它差點兒是全天工作的,是以它能夠在不論什麼時候為使用者提供服務,後面将提到這正是為什麼須要郵件server的一個重要原因。非常多ISP都提供免費的郵件server,如126提供smtp.126.com郵件server。
郵件server向其他郵件server轉發郵件也是採用SMTP協定。
1.3. 郵件的收發過程
普通情況下,一封郵件的發送和接收步驟例如以下。
1) 發信人在使用者代理裡編輯郵件,包含填寫發信人郵箱、收信人郵箱和郵件标題等等。
2) 使用者代理提取發信人編輯的資訊,生成一封符合郵件格式标準(RFC822)的郵件。
3) 使用者代理用SMTP将郵件發送到發送端郵件server(即發信人郵箱所相應的郵件server)。
4) 發送端郵件server用SMTP将郵件發送到接收端郵件server(即收信人郵箱所相應的郵件server)。
5) 收信人調用使用者代理。使用者代理用POP3協定從接收端郵件server取回郵件。
6) 使用者代了解析收到的郵件,以适當的形式呈如今收信人面前。
第2章. SMTP具體解釋
2.1. 通信過程
一個詳細的SMTP通信(如發送端郵件server與接收端server的通信)的步驟例如以下。
1) 發送端郵件server(下面簡稱client)與接收端郵件server(下面簡稱server)的25号port建立TCP連接配接。
2) client向server發送各種指令,來請求各種服務(如認證、指定發送人和接收人)。
3) server解析使用者的指令,做出對應動作并傳回給client一個響應。
4) 2)和3)交替進行,直到全部郵件都發送完或兩者的連接配接被意外中斷。
從這個過程看出,指令和響應是SMTP協定的重點,以下将予以重點講述。
2.2. 指令和響應
2.2.1. 格式
SMTP的指令不多(14個),它的一般形式是:COMMAND [Parameter] <CRLF>。當中COMMAND是ASCII形式的指令名,Parameter是對應的指令參數,<CRLF>是回車換行符(0DH, 0AH)。
SMTP的響應也不複雜,它的一般形式是:XXX Readable Illustration。XXX是三位十進制數;Readable Illustration是可讀的解釋說明,用來表明指令是否成功等。XXX具有例如以下的規律:以2開頭的表示成功,以4和5開頭的表示失敗,以3開頭的表示未完畢(進行中)。
2.2.2. 一個樣例
指令和響應的格式是文法,各指令和響應的意思則是語義,各指令和各響應在時間上的關系則是同步。以下将通過一個簡單的SMTP通信過程來說明協定的這三個要素。
C:telnet smtp.126.com 25 /* 以telnet方式連接配接126郵件server */
S:220 126.com Anti-spam GT for Coremail System (126com[071018]) /* 220為響應數字,其後的為歡迎資訊,會應server不同而不同*/
C:HELO smtp.126.com /* HELO 後用來填寫傳回域名(詳細含義請參閱RFC821),但該指令并不檢查後面的參數 */
S:250 OK
C: MAIL FROM: [email protected] /* 發送者郵箱 */
S:250 … ./* “…”代表省略了一些可讀資訊 */
C:RCPT TO: [email protected] /* 接收者郵箱 */
C:DATA /* 請求發送資料 */
S:354 Enter mail, end with "." on a line by itself
C:Enjoy Protocol Studing
C:.
S:250 Message sent
C:QUIT /* 退出連接配接 */
S:221 Bye
分析上面的過程可參考凝視進行,這裡要補充例如以下幾點。
1) “C:”開頭的行(不包含"C:")是client的輸入,而以“S:”開頭的行(不包含"S:")則是server的輸出。
2) 上述的指令并不一定會一次性成功,server會傳回錯誤響應,client應該依照協定規定的時序,來輸入興許的指令(或反複運作失敗的指令,或重置會話,或退出會話等等)。
2.2.3. 經常使用指令
SMTP指令不區分大寫和小寫,但參數區分大寫和小寫,有關這方面的具體說明請參考RFC821。經常使用的指令例如以下。
HELO <domain> <CRLF>。向server辨別使用者身份發送者能欺騙,說謊,但普通情況下server都能檢測到。
MAIL FROM: <reverse-path> <CRLF>。<reverse-path>為發送者位址,此指令用來初始化郵件傳輸,即用來對全部的狀态和緩沖區進行初始化。
RCPT TO:<forward-path> <CRLF>。 <forward-path>用來标志郵件接收者的位址,經常使用在MAIL FROM後,能夠有多個RCPT TO。
DATA <CRLF>。将之後的資料作為資料發送,以<CRLF>.<CRLF>标志資料的結尾。
REST <CRLF>。重置會話,目前傳輸被取消。
NOOP <CRLF>。要求server傳回OK應答,一般用作測試。
QUIT <CRLF>。結束會話。
VRFY <string> <CRLF>。驗證指定的郵箱是否存在,因為安全方面的原因,server大多禁止此指令。
EXPN <string> <CRLF>。驗證給定的郵箱清單是否存在,因為安全方面的原因,server大多禁止此指令。
HELP <CRLF>。查詢server支援什麼指令。
2.2.4. 經常使用響應
經常使用的響應例如以下所看到的,數字後的說明是從英文譯過來的。更具體的說明請參考RFC821。
501參數格式錯誤
502指令不可實作
503錯誤的指令序列
504指令參數不可實作
211系統狀态或系統幫助響應
214幫助資訊
220<domain>服務就緒
221<domain>服務關閉
421<domain>服務未就緒,關閉傳輸信道
250要求的郵件操作完畢
251使用者非本地,将轉發向<forward-path>
450要求的郵件操作未完畢,郵箱不可用
550要求的郵件操作未完畢,郵箱不可用
451放棄要求的操作;處理過程中出錯
551使用者非本地,請嘗試<forward-path>
452系統存儲不足,要求的操作未運作
552過量的存儲配置設定,要求的操作未運作
553郵箱名不可用,要求的操作未運作
354開始郵件輸入,以"."結束
554操作失敗
第3章. SMTP的擴充
3.1. SMTP的缺點
從2.2.2的樣例能夠看出,SMTP至少還有例如以下缺點。
1) 指令過于簡單,沒提供認證等功能。
2) 僅僅傳送7位的ASCII碼,不能傳送二進制檔案。
針對缺點1),标準化組織制定了擴充的SMTP(即ESMTP),相應的RFC文檔為RFC1425。針對缺點2),标準化組織在相容SMTP的前提下,提出了傳送非7位ASCII碼的方法,相應的RFC文檔有兩個:郵件首部的擴充相應于RFC1522,郵件正文的擴充相應與RFC1521(即MIME)。
3.2. ESMTP
ESMTP最顯著的地方是加入了使用者認證功能。假設使用者想使用ESMTP提供的新指令,則在初次與server互動時,發送的指令應該是EHLO而不是HELO。先來看一個樣例。
C:EHLO smtp.126.com /* 除了HELO所具有的功能外,EHLO主要用來查詢server支援的擴充功能 */
S:250-mail
S:250-AUTH LOGIN PLAIN
S:250-AUTH=LOGIN PLAIN
S:250 8BITMIME /* 最後一個響應數字應答碼之後跟的是一個空格,而不是'-' */
C:AUTH LOGIN /* 請求認證 */
S:334 dxNlcm5hbWU6 /* server的響應——經過base64編碼了的“Username” */
C:Y29zdGFAYW1heGl0Lm5ldA== /* 發送經過BASE64編碼了的username */
S:334 UGFzc3dvcmQ6 /* 經過BASE64編碼了的"Password:" */
C:MTk4MjIxNA== /* client發送的經過BASE64編碼了的password */
S:235 auth successfully /* 認證成功 */
對于這個樣例有例如以下幾點說明。
1) 僅僅是一個示意性的過程,再輸入username、password時需採用base64編碼,這須要專門的計算,是以在telnet終端上模拟比較麻煩。
2) 認證過程有非常多種,有基于明文的認證,也有基于MD5加密的認證,這裡給出的僅僅是一個示意性的過程。
3) EHLO對于詳細server,響應會不同,keyword“8BITMIME”用來說明server是否支援正文中傳送8位ASCII碼,而以“X”開頭的keyword都是指server自己定義的擴充(還沒納入RFC标準)
更具體的說明,請參看RFC1425。
3.3. 郵件首部的擴充
首部通過兩種編碼方式來支援傳送非7位ASCII碼。它首先通過一個例如以下格式的編碼字來表明所用的編碼方式。
=?charset?encoding?encoded-text?text
charset是字元集規範。有效值是兩個字元串us-ascii和iso-8859-x,當中x 是一個單個數字,比如iso-8859-1中的數字為“ 1”。
encoding是一個單個字元用來指定編碼方法,支援兩個值。
Q代表quoted-printable(可列印)編碼。不論什麼要發送的字元若其第8比特置1則被作為3個字元發送:第1個是字元是“=”,後面的兩個字元相應于字元的十六進制表示。比如對于二進制碼11111111,其相應的十六進制表示為“FF”,是以相應的編碼位“=FF”。為了可以傳輸“=”,“=”的編碼方式與第8比特置1的字元同樣,由于其二進制代碼為00111101,是以相應的編碼為“=3D”。可以看出這樣的編碼方式的開銷達200%,是以僅僅适合傳送僅僅含有少量非7位ASCII碼的文本。
B代表base64編碼。它的編碼方法是先将二進制代碼劃分為一個24bit長的單元,然後将這24 bit單元劃分為4個6 bit組。每一個組按圖 2所看到的的方法轉換成ASCII碼。
圖 2 base64映射表
能夠看出這種映射方法是這種:0-25依次映射成A-Z,26-51依次映射成a-z,52-61依次映射成數字0-9,然後62映射成+,63映射成/。
對于二進制代碼01001001 00110001 01111001,先将其劃分成4個6 bit組,即010010 0100011 000101 111001。接着按圖 2所看到的的映射表,可得到base64編碼為:STF5。能夠看出,這樣的編碼方式的開銷是25%,相對quoted-printable編碼來說,它更适合用來傳送含大量非7位ASCII碼的二進制檔案。
3.4. 正文的擴充
正文的擴充主要是使正文不僅能夠傳輸NVT ASCII字元,并且能夠傳輸随意字元,相應的文檔為RFC1511(即MIME)。
MIME全稱為“Multiple Internet Mail Extensions”, 比較确切的中文名稱為“多用途網際網路郵件擴充”。它通過新增一些郵件首部字段、郵件内容格式和傳送編碼,使得其成為一種應用非常廣泛的能夠傳輸多媒體的電子郵件規範。
更具體的說明請參看還有一篇文章《MIME協定分析》和RFC1511。
第4章. 常見的疑問
4.1. 為什麼須要SMTPserver
一般的PC資源不夠,處理能力不夠,不可能全天候地連接配接在網際網路上來收發郵件。是以使用SMTPserver,能夠讓多個使用者共用server,有效地減少了成本。
4.2. SMTP和郵件格式的關系
如前所述,SMTP是客戶機向server發送郵件時所使用的協定,其核心是2.2中所述的指令和響應,至于它指令和響應中所帶的參數採用什麼格式,則是依賴于其它标準的。比如DATA後所帶的參數,則應遵循郵件格式标準RFC822.
SMTP和郵件格式的關系可用這麼一個樣例來說明。甲與乙書信往來,甲通過郵局向乙發信,郵局間轉交郵件可看成使用了SMTP協定,至于書信的格式則會由于地區習慣等的不同而不同(中國人的書信格式和美國人的書信格式不同),這個書信格式則可看成是郵件格式标準。
應當認識到不能孤立地看待協定,各個協定之間往往存在着耦合關系,但為了分析友善,我們在詳細叙述某個協定時,僅僅能抓住主要沖突——主要闡述單個協定。
4.3. 浏覽器發送郵件用的什麼協定
浏覽器如IE、Maxthon可通過登陸使用者郵箱,來收發郵件,這是如何實作的?比如[email protected]可通過登陸www.126.com來收發郵件。
這個過程是這種:[email protected]在www.126.com提供的郵件頁面上填寫的對應資訊(如發信人郵箱、收信人郵箱等),通過http協定被送出給126server;126server依據這些資訊組裝一封符合郵件規範的郵件(就像使用者代理一樣);然後smtp.126.com通過SMTP協定将這封郵件發送到接收端郵件server。
能夠看出,浏覽器發送郵件僅僅是使用者代理的功能直接放到郵件server上去做了,至于郵件server間發送郵件還是採用的SMTP協定。我們看問題,假設有必要還是要适當地透過現象看本質。
4.4. 怎樣用實驗驗證SMTP的通信過程
1) 能夠通過ethereal等協定分析軟體來抓包分析協定。
2) 能夠利用socket程式設計實作SMTP的通信過程。
3) 能夠利用使用者代理來檢視一封郵件的原始編碼。比如在Foxmail中,能夠選擇郵件清單右鍵菜單的“原始資訊”進行檢視。
第5章. 分析方案
ID | Protocol | Captured contents | |||||
user name | password | sender | receiver | subject | contents | attachments | |
4 | smtp | √ |
表 1 協定分析要求
表 1給出了協定分析要求。easy看出,擷取各個字段是比較easy的。我們可以抓取client與server端的互動資訊,然後依據各指令字或響應字來提取出我們想要的字段。比如,要擷取user name,我們僅僅需檢測到server端要求client發送username這個時候,然後提取這之後client的發送資訊就可以。須要說明的是,盡管client與服務端互動的資訊可能經過了編碼或加密,但我們仍可以通過解碼或解密來獲得所須要的資訊。
第6章. 參考資料
[1] RFC文檔:RFC821相應SMTP協定,RFC822相應郵件标準,RFC1425相應ESMTP,RFC1522相應郵件首部的擴充,RFC1521相應郵件正文的擴充,RFC1939相應POP3協定。
[2] http://www.faqs.org/rfcs/,上面有全面的英文RFC文檔
[3] http://www.cnpaf.net/,上面有不少實用的協定分析文檔,也有中文RFC文檔,但品質不是特别高
[4] Stevens, W.R., TCP/IP Illustrated, Vol1. Addision-Wesley, 機械工業出版社,2002