SMTP

簡單郵件傳輸協議

SMTP(SimpleMailTransferProtocol)簡單郵件傳輸協議是一種提供可靠且有效電子郵件傳輸的協議。SMTP是建模在FTP文件傳輸服務上的一種郵件服務,主要用於傳輸系統之間的郵件信息並提供來信有關的通知。SMTP獨立於特定的傳輸子系統,且只需要可靠有序的數據流通道支持。SMTP重要特性之一是其能跨越網路傳輸郵件,即“SMTP郵件中繼”。通常,一個網路可以由公用網際網路上TCP可相互訪問的主機、防火牆分隔的TCP/IP網路上TCP可相互訪問的主機,及其它LAN/WAN中的主機利用非TCP傳輸層協議組成。使用SMTP,可實現相同網路上處理機之間的郵件傳輸,也可通過中繼器網關實現某處理機與其它網路之間的郵件傳輸。在這種方式下,郵件的發送可能經過從發送端到接收端路徑上的大量中間中繼器或網關主機。域名服務系統(DNS)的郵件交換伺服器可以用來識別出傳輸郵件的下一跳IP地址。

簡介


SMTP是一個相對簡單的基於文本的協議。在其之上指定了一條消息的一個或多個接收者(在大多數情況下被確認是存在的),然後消息文本會被傳輸。可以很簡單地通過telnet程序來測試一個SMTP伺服器。SMTP使用TCP埠25。要為一個給定的域名決定一個SMTP伺服器,需要使用MX(MaileXchange)DNS。
在八十年代早期SMTP開始被廣泛地使用。當時,它只是作為UUCP的補充,UUCP更適合於處理在間歇連接的機器間傳送郵件。相反,SMTP在發送和接收的機器在持續連線的網路情況下工作得最好。
Sendmail是最早使用SMTP的郵件傳輸代理之一。到2001年至少有50個程序將SMTP實現為一個客戶端(消息的發送者)或一個伺服器(消息的接收者)。一些其他的流行的SMTP伺服器程序包括了PhilipHazel的exim,IBMPostfix,D.J.Bernstein的Qmail,以及MicrosoftExchangeServer。由於這個協議開始是基於純ASCII文本的,它在二進位文件上處理得並不好。諸如MIME的標準被開發來編碼二進位文件以使其通過SMTP來傳輸。今天,大多數SMTP伺服器都支持8位MIME擴展,它使二進位文件的傳輸變得幾乎和純文本一樣簡單。 SMTP是一個“推”的協議,它不允許根據需要從遠程伺服器上“拉”來消息。要做到這點,郵件客戶端必須使用POP3IMAP。另一個SMTP伺服器可以使用ETRN在SMTP上觸發一個發送。

SMTP通信舉例


下面通過一個實例進行說明。在本例中,假設郵件從名為[email protected]的發件人電子郵件箱(運行SMTP客戶進程,具體顯示為C)傳送到名為[email protected]的收件人電子信箱(運行SMTP伺服器進程,具體顯示為S),具體的命令和響應信息如下:telnetwww.example.com25它打開一個從發送的機器到主機www.example.com的SMTP連接。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
S:(註:等待連接TCP的25號埠,該埠對應SMTP服務)
C:(註:打開與伺服器的連接)
S:220 xmu. edu. cn SMTP Service ready(註:伺服器的TCP連接就緒)
C:HELO 163.com
S:250 xmu. edu. cn says hello
C:MAIl. FROM:
S:250 0K
C:RCPT TO:
S:250 0K
C:DATA
S:354 Start mail input; end with.
C:…sends body of mail message..
C:…Dear xxx..
C:
S:250 OK
C:QUIT
S:221 xmu. edu. cn Service closing transmission channel
以上所示的是一個簡單的SMTP交換過程,包括了連接建立、郵件傳送和連接釋放三個具體過程:首先建立TCP連接,SMTP調用TCP協議的25號埠監聽連接請求,客戶端發送HElO命令以標識發件人自己的身份,伺服器做出響應。然後,客戶端發送MAII)命令,伺服器以OK作為Ⅱ嚮應,表明準備接收。客戶端發送RCPT命令以標識電子郵件的收件人,可以有多個RCPT行,即一份郵件可以同時發送給多個收件人。伺服器端則表示是否願意為收件人接收郵件。協商結束后,客戶端用DATA命令發送信息,以<CRLF>表示結束輸入內容。最後,控制交互的任一端可選擇終止會話,為此它發出一個QUIT命令,另一端用命令221響應,表示同意終止連接,雙方將關閉連接。 
SMTP交換過程中伺服器端發出的“2500K”含義是一切都好。與使用其他協議一樣,程序只讀縮寫命令和每行開頭的三個數字,其餘文本是用於幫助用戶調試郵件軟體。在命令成功時,伺服器返回代碼250,如果失敗則返回代碼550(命令無法識別)、451(處理時出錯)、452(存儲空間不夠)、421(伺服器不可用)等,354則表示開始信息輸入。
SMTP的局限性表現在只能發送ASCII碼格式的報文,不支持中文、法文、德文等,它也不支持語音、視頻的數據。通過MIME協議,對SMTP補充。MIME使用網路虛擬終端(NVT)標準,允許非ASCII碼數據通過SMTP傳輸。

SMTP安全和垃圾郵件


最初的SMTP的局限之一在於它沒有對發送方進行身份驗證的機制。因此,後來定義了SMTP-AUTH擴展。
儘管有了身份認證機制,垃圾郵件仍然是一個主要的問題。但由於龐大的SMTP安裝數量帶來的網路效應,大刀闊斧地修改或完全替代SMTP被認為是不現實的。InternetMail2000就是一個替代SMTP的建議方案。
因此,出現了一些同SMTP工作的輔助協議。IRTF的反垃圾郵件研究小組正在研究一些建議方案,以提供簡單、靈活、輕量級的、可升級的源端認證。最有可能被接受的建議方案是發件人策略框架協議。

工作過程


SMTP協議的工作過程可分為如下3個過程:
(1)建立連接:在這一階段,SMTP客戶請求與伺服器的25埠建立一個TCP連接。一旦連接建立,SMTP伺服器和客戶就開始相互通告自己的域名,同時確認對方的域名。
(2)郵件傳送:利用命令,SMTP客戶將郵件的源地址、目的地址和郵件的具體內容傳遞給SMTP伺服器,SMTP伺服器進行相應的響應並接收郵件。
(3)連接釋放:SMTP客戶發出退出命令,伺服器在處理命令後進行響應,隨後關閉TCP連接。

功能


SMTP是一組用於從源地址到目的地址傳送郵件的規則,並且控制信件的中轉方式。SMTP協議屬於TCP/IP協議族,它幫助每台計算機在發送或中轉信件時找到下一個目的地。通過SMTP協議所指定的伺服器,我們就可以把E—mail寄到收信人的伺服器上了,整個過程只需要幾分鐘。SMTP伺服器是遵循SMTP協議的發送郵件伺服器,用來發送或中轉用戶發出的電子郵件。
SMTP是一種提供可靠且有效電子郵件傳輸的協議。它是建立在FTP文件傳輸服務上的一種郵件服務,主要用於傳輸系統之間的郵件信息並提供來信有關的通知。
SMTP重要的特性之一是它能跨越網路傳輸郵件,也即“SMTP郵件中繼”。使用SMTP,可實現相同網路上處理機之間的郵件傳輸,也可以通過中繼器或網關實現某處理機與其它網路之間的郵件傳輸。具有域名服務系統(DNS)功能的郵件交換伺服器還可以用來識別出傳輸郵件的下一跳IP地址。

協議原理


SMTP-簡單郵件傳輸協議(SimpleMailTransferProtocol),是定義郵件傳輸的協議,它是基於TCP服務的應用層協議,由RFC0821所定義。SMPT協議規定的命令是以明文方式進行的。為了說明SMTP的工作原理,我們以向163發送郵件為實例進行說明。
linux環境下,使用"telnet smtp.163.com25"連接smtp.163.com的25號埠(SMTP的標準服務埠);在windows下使用telnet程序,遠程主機指定為smtp.163.com,而埠號指定為25,然後連接smtp.163.com:交互過程如下:
[lix@nslix]$telnetsmtp.163.com25
220163.comAnti-spamGTforCoremailSystem(163com[071018])
helosmtp.163.com
250OK
authlogin
334dXNlcm5hbWU6
USERbase64加密后的用戶名
334UGFzc3dvcmQ6
PASSbase64加密后的密碼
235Authenticationsuccessful
250MailOK
250MailOK
DATA
354Enddatawith.
QUIT
250MailOKqueuedassmtp5,D9GowLArizfIFTpIxFX8AA==.41385S21211766217
SMTP
SMTP
HELO是客戶向對方郵件伺服器發出的標識自己的身份的命令,這裡假設發送者為ideal;MAILFROM命令用來表示發送者的郵件地址;RCPTTO:標識接收者的郵件地址,這裡表示希望發送郵件給[email protected],如果郵件接收者不是本地用戶,例如RCPTTO:[email protected],則說明希望對方郵件伺服器為自己轉發(Relay)郵件,若該機器允許轉發這樣的郵件,則表示該郵件伺服器是OPENRELAY的,否則說明該伺服器不允許RELAY;DATA表示下面是郵件的數據部分,輸入完畢以後,以一個"."開始的行作為數據部分的結束標識;QUIT表示退出這次會話,結束郵件發送。
這就是一個簡單的發送郵件的會話過程,其實當使用outlookexpress等客戶軟體發送時,後台進行的交互也是這樣的,當然,SMTP協議為了處理複雜的郵件發送情況如附件等等,定義了很多的命令及規定,具體可以通過閱讀RFC821來獲得。
當你的一個朋友向你發送郵件時,他的郵件伺服器和你的郵件伺服器通過SMTP協議通信,將郵件傳遞給你郵件地址所指示的郵件伺服器上(這裡假設你的本地郵件伺服器是Linux系統),若你通過telnet協議直接登錄到郵件伺服器上,則可以使用mail等客戶軟體直接閱讀郵件,但是若你希望使用本地的MUA(MailUserAgent,如outlookexpress等客戶軟體)來閱讀郵件,則本地客戶端通過POP3或IMAP協議與郵件伺服器交互,將郵件信息傳遞到客戶端(如:win98系統)。而如果你向你的朋友回復一封信件時,你所使用的MUA也是通過SMTP協議與郵件服務(一般為發送郵件地址對應的email地址)器通信,指示其希望郵件伺服器幫助轉發一封郵件到你朋友的郵件地址指定的郵件伺服器中。若本地郵件伺服器允許你通過它轉發郵件,則伺服器通過SMTP協議發送郵件到對方的郵件伺服器。這就是接受和發送郵件的全部過程。

郵件伺服器


郵件伺服器一般具有一個或若干個域名(這些域名應該出現在某個配置文件內),郵件伺服器在運行時將監聽25號埠,等待遠程的發送郵件的請求。網路上其他的mail伺服器或者請求發送郵件的MUA(MailUserAgent,如outlookexpress、foxmail等等)會連接郵件伺服器的25號埠,請求發送郵件,SMTP會話過程一般是從遠程標識自己的身份開始,過程如下:
HELOremote.system.domainname
250qmailserver.domain
250OK
郵件的接收者[email protected]中的域名並不一定是郵件接受伺服器的所具有的本地域名,也就是說郵件目的可能不是上面協議交互中的接收方,而是郵件發送者希望接收郵件伺服器幫助其轉發郵件。這時候本地系統可能有兩種回答,接受它:
250OK
或者拒絕接受它:
553sorry,.thatdomainisnotinmydomainlistofallowedrecphosts
第一種情況下,本地郵件伺服器是允許relay的,它接收並同意傳遞一個目的地址不是本地的郵件;而第二種情況則不接收非本地郵件。
不能配置郵件伺服器為openrelay的原因
如果系統管理員將自己的郵件伺服器設置為openrelay,將會導致一些垃圾郵件發送者將你的郵件伺服器作為轉發自圾郵件的中繼站,這將使垃圾郵件的接收者將矛頭對準你,可能會導致報復性的郵件炸彈;垃圾郵件還能消耗你大量的資源,佔用你的帶寬。更為糟糕的事情可能是你的名字可能會上了黑名單,成為其他郵件接收者共同抵制的目標,你的郵件將被這些接收者所拒絕。

協議程序實現


socket連接郵件伺服器實現SMTP協議的PHP程序:
<?php
classsmtp
{
public$bd;
public$cntid;
public$host;
public$port=25;
public$errno;
public$message=array();
private$user;
private$pass;
function__construct(&$bd)
{
$this->bd=$bd;
}
functionsendData($order,$bool)
{
fputs($this->cntid,$order."\n");
if($bool)returnfgets($this->cntid,1024).'<hr/>';
elsereturntrue;
}
functionmail($from,$to,$message,$user,$pass,$host,$port=25,$timeout=30)
{
if($from)$this->from=$from;
if($to)$this->to=$to;
if($user)$this->user=base64_encode($user);
if($pass)$this->pass=base64_encode($pass);
if($host)$this->host=$host;
if($port)$this->port=$port;
if(!$this->host)
{
$this->errno=1;
returnfalse;
}
if(!function_exists('fsockopen'))
{
$this->errno=2;
returnfalse;
}
$this->cntid=@fsockopen($this->host,$this->port,$errno,$errstr,$timeout);
$back=$this->sendData('helo'.$this->host);
if(substr($back,0,3)!=250)
{
$this->errno=3;
returnfalse;
}
if($this->user)
{
$back=$this->sendData('authlogin');
if(substr($back,0,3)!=334)
{
$this->errno=4;
returnfalse;
}
$back=$this->sendData('user'.$this->user);
if(substr($back,0,3)!=334)
{
$this->errno=4;
returnfalse;
}
$back=$this->sendData('user'.$this->user);
if(substr($back,0,3)!=235)
{
$this->errno=4;
returnfalse;
}
}
$back=$this->sendData('mailfrom:<'.$this->from.'>');
if(substr($back,0,3)!=250)
{
$this->errno=5;
returnfalse;
}
if(is_array($this->to))
{
foreach($this->toas$p)
{
$back=$this->sendData('rcptto:<'.$p.'>');
if(substr($back,0,3)!=250)
{
$this->errno=6;
returnfalse;
}
}
}
else
{
$back=$this->sendData('rcptto:<'.$this->to.'>');
if(substr($back,0,3)!=250)
{
$this->errno=6;
returnfalse;
}
}
$back=$this->sendData('data');
if(substr($back,0,3)!=354)
{
$this->errno=7;
returnfalse;
}
$this->sendData('Content-Type:text/plain;chaRSet="'.HE.'"'."\n".'MIME-Version:1.0',false);
if(is_array($this->to))
{
foreach($this->toas$p)
{
$this->sendData('to:<'.$p.'>',false);
}
}
else$this->sendData('to:<'.$this->to.'>',false);
$this->sendData('from:'.$user.'<'.$this->to.'>',false);
if($this->message['subject'])$this->sendData('subject:'.$this->message['subject'],false);
if($this->message['body'])
{
$this->sendData('');
$this->sendData('');
$this->sendData($this->message['body'],false);
}
$back=$this->sendData('quit');
{
$this->errno=8;
returnfalse;
}
}
}
$smtp=newsmtp;
smtp->mail($from,$to,$message,$user,$pass,$host,$port=25,$timeout);
?>

通訊模型


SMTP
SMTP
SMTP協議是TCP/IP協議族中的一員,主要對如何將電子郵件從發送方地址傳送到接收方地址,也即是對傳輸的規則做了規定。SMTP協議的通信模型並不複雜,主要工作集中在發送SMTP和接收SMTP上:首先針對用戶發出的郵件請求,由發送SMTP建立一條連接到接收SMTP的雙工通訊鏈路,這裡的接收SMTP是相對於發送SMTP而言的,實際上它既可以是最終的接收者也可以是中間傳送者。發送SMTP負責向接收SMTP發送SMTP命令,而接收SMTP則負責接收並反饋應答。
SMTP協議的命令和應答
從前面的通訊模型可以看出SMTP協議在發送SMTP和接收SMTP之間的會話是靠發送SMTP的SMTP命令和接收SMTP反饋的應答來完成的。在通訊鏈路建立后,發送SMTP發送MAIL命令指令郵件發送者,若接收SMTP此時可以接收郵件則作出OK的應答,然後發送SMTP繼續發出RCPT命令以確認郵件是否收到,如果接收到就作出OK的應答,否則就發出拒絕接收應答,但這並不會對整個郵件操作造成影響。雙方如此反覆多次,直至郵件處理完畢。SMTP協議共包含10個SMTP命令,列表如下:
SMTP命令命令說明
HELLO<domain><CRLF>識別發送方到接收SMTP的一個HELLO命令
MAILFROM:<reverse-path><CRLF><reverse-path>為發送者地址。此命令告訴接收方一個新郵件發送的開始,並對所有的狀態和緩衝區進行初始化。此命令開始一個郵件傳輸處理,最終完成將郵件數據傳送到一個或多個郵箱中。
RCPTTO:<forward-path><CRLF><forward-path>標識各個郵件接收者的地址
DATA<CRLF>
接收SMTP將把其後的行為看作郵件數據去處理,以<CRLF>.<CRLF>標識數據的結尾。
REST<CRLF>退出/複位當前的郵件傳輸
Noop<CRLF>要求接收SMTP僅做OK應答。(用於測試)
QUIT<CRLF>要求接收SMTP返回一個OK應答並關閉傳輸。
VRFY<string><CRLF>驗證指定的郵箱是否存在,由於安全因素,伺服器多禁止此命令。
EXPN<string><CRLF>驗證給定的郵箱列表是否存在,擴充郵箱列表,也常禁止使用。
HELP<CRLF>查詢伺服器支持什麼命令

安全


sendmail是在Unix環境下使用最廣泛的實現郵件發送/接受的郵件傳輸代理程序。由於Sendmail郵件伺服器的特點是功能強大而複雜,因此為保證Sendmail的安全性,需要作以下一些工作。
1、設置Sendmail使用"smrsh"
smrsh程序的目的是作為在mailer中為sendmail定義的"/bin/sh"的替代shell。smrsh是一種受限shell工具,它通過"/
SMTP
SMTP
etc/smrsh"目錄來明確指定可執行文件的列表。簡而言之smrsh限制了攻擊者可以執行的程序集。當它與sendmail程序一起使用的時候,smrsh有效的將sendmail可以執行的程序的範圍限制在smrsh目錄之下。
第一步:
決定smrsh可以允許sendmail運行的命令列表。預設情況下應當包含以下命令,但不局限於這些命令:
"/bin/mail"(如果在你的系統中安裝了的話)
"/usr/bin/procmail"(如果在你的系統中安裝了的話)
注意:不可在命令列表裡包括命令解釋程序,例如sh(1),CSH(1),perl(1),uudecode(1)及流編輯器sed(1)。
第二步:
在"/etc/smrsh"目錄中創建允許sendmail運行的程序的符號連接。
使用以下命令允許mail程序"/bin/mail"運行:
[root@deep]#cd/etc/smrsh
[root@deep]#ln-s/bin/mailmail
用以下命令允許procmail程序"/usr/bin/procmail"運行:
[root@deep]#cd/etc/smrsh
[root@deep]#ln-s/usr/bin/procmailprocmail
這將允許位於".forward"和"aliases"中的用戶採用"|program"語法來運行mail及procmail程序。
第三步
配置sendmail使之使用受限shell。mailer程序在sendmail的配置文件"/etc/sendmail.cf"中僅有一行。必須修改"sendmail.cf"文件中"Mprog"定義的那一行。將"/bin/sh"替換為"/usr/sbin/smrsh"。
編輯"sendmail.cf"文件(vi/etc/sendmail.cf)並改動下面這一行:
例如:
Mprog,P=/bin/sh,F=lsDFMoqeu9,S=10/30,R=20/40,D=$z:/,T=X-Unix,A=sh-c$u
應該被改為:
Mprog,P=/usr/sbin/smrsh,F=lsDFMoqeu9,S=10/30,R=20/40,D=$z:/,T=X-Unix,A=sh-c$u
現在用以下命令手工重起sendmail進程:
[root@deep]#/etc/rc.d/init.d/sendmailrestart
2、"/etc/aliases"文件
如果沒有加以正確和嚴格的管理的話,別名文件被用來獲取特權。例如,很多發行版本在別名文件中帶有"decode"別名。現在這種情況越來越少了。
這樣做的目的是為用戶提供一個通過mail傳輸二進位文件的方便的方式。在郵件的發送地,用戶把二進位文件用"uuencode"轉換成ASCII格式,並把結果郵遞給接收地"decode"別名。那個別名通過管道把郵件消息發送到"/usr/bin/uuencode"程序,由這個程序來完成從ASCII轉回到原始的二進位文件的工作。
刪除"decode"別名。類似的,對於所有用於執行沒有被放在smrsh目錄下的程序的別名,你都要仔細的檢查,可能它們都值得懷疑並應當刪除它們。要想使你的改變生效,需要運行:
[root@deep]#/usr/bin/newaliases
編輯別名文件(vi/etc/aliases)並刪除以下各行:
#Basicsystemaliases--theseMUSTbepresent.
MAILER-DAEMON:postmaster
postmaster:root
#Generalredirectionsforpseudoaccounts.
bin:root
daemon:root
games:root??刪除這一行
ingres:root??刪除這一行
nobody:root
system:root??刪除這一行
toor:root??刪除這一行
uucp:root??刪除這一行
#Well-knownaliases.
manager:root??刪除這一行
dumper:root??刪除這一行
operator:root??刪除這一行
#trapdecodetocatchsecurityattacks
decode:root??刪除這一行
#Personwhoshouldgetroot'smail
#root:marc
最後應該運行"/usr/bin/newaliases"程序使改動生效
3、避免你的Sendmail被未授權的用戶濫用
最新版本的Sendmail(8.9.3)加入了很強的防止欺騙的特性。它們可以防止你的郵件伺服器被未授權的用戶濫用。編輯你的"/etc/sendmail.cf"文件,修改一下這個配置文件,使你的郵件伺服器能夠擋住欺騙郵件。
編輯"sendmail.cf"文件(vi/etc/sendmail.cf)並更改下面一行:
OPrivacyOptions=authwarnings
改為:
OPrivacyOptions=authwarnings,noexpn,novrfy
設置"noexpn"使sendmail禁止所有SMTP的"EXPN"命令,它也使sendmail拒絕所有SMTP的"VERB"命令。設置"novrfy"使sendmail禁止所有SMTP的"VRFY"命令。這種更改可以防止欺騙者使用"EXPN"和"VRFY"命令,而這些命令恰恰被那些不守規矩的人所濫用。
4、SMTP的問候信息
當sendmail接受一個SMTP連接的時候,它會向那台機器發送一個問候信息,這些信息作為本台主機的標識,而且它所做的第一件事就是告訴對方它已經準備好了。
編輯"sendmail.cf"文件(vi/etc/sendmail.cf)並更改下面一行:
OSmtpGreetingMessage=$jSendmail$v/$Z;$b
改為:
OSmtpGreetingMessage=$jSendmail$v/$Z;$bNOUCEC=xxL=xx
現在手工重起一下sendmail進程,使剛才所做的更改生效:
[root@deep]#/etc/rc.d/init.d/sendmailrestart
以上的更改將影響到Sendmail在接收一個連接時所顯示的標誌信息。你應該把"`C=xxL=xx"條目中的"xx"換成你所在的國家和地區代碼。後面的更改其實不會影響任何東西。但這是"news.admin.net-abuse.email"新聞組的夥伴們推薦的合法做法。
5、限制可以審核郵件隊列內容的人員
通常情況下,任何人都可以使用"mailq"命令來查看郵件隊列的內容。為了限制可以審核郵件隊列內容的人員,只需要在"/etc/sendmail.cf"文件中指定"restrictmailq"選項即可。在這種情況下,sendmail只允許與這個隊列所在目錄的組屬主相同的用戶可以查看它的內容。這將允許許可權為0700的郵件隊列目錄被完全保護起來,而我們限定的合法用戶仍然可以看到它的內容。
編輯"sendmail.cf"文件(vi/etc/sendmail.cf)並更改下面一行:
OPrivacyOptions=authwarnings,noexpn,novrfy
改為:
OPrivacyOptions=authwarnings,noexpn,novrfy,restrictmailq
現在我們更改郵件隊列目錄的許可權使它被完全保護起來:
[root@deep]#chmod0700/var/spool/mqueue
注意:我們已經在sendmail.cf中的"PrivacyOptions="行中添加了"noexpn"和"novrfy"選項,現在在這一行中我們接著添加"restrictmailq"選項。
任何一個沒有特權的用戶如果試圖查看郵件隊列的內容會收到下面的信息:
[user@deep]$/usr/bin/mailq
Youarenotpermittedtoseethequeue
SMTP
SMTP
6、限制處理郵件隊列的許可權為"root"通常,任何人都可以使用"-q"開關來處理郵件隊列,為限制只允許root處理郵件隊列,需要在"/etc/sendmail.cf"文件中指定"restrictqrun"。
編輯"sendmail.cf"文件(vi/etc/sendmail.cf)並更改下面一行:
OPrivacyOptions=authwarnings,noexpn,novrfy,restrictmailq
改為:
OPrivacyOptions=authwarnings,noexpn,novrfy,restrictmailq,restrictqrun
任何一個沒有特權的用戶如果試圖處理郵件隊列的內容會收到下面的信息:
[user@deep]$/usr/sbin/sendmail-q
Youdonothavepermissiontoprocessthequeue
7、在重要的sendmail文件上設置不可更改位
可以通過使用"chattr"命令而使重要的Sendmail文件不會被擅自更改,可以提高系統的安全性。具有"+i"屬性的文件不能被修改:它不能被刪除和改名,不能創建到這個文件的鏈接,不能向這個文件寫入數據。只有超級用戶才能設置和清除這個屬性。
為"sendmail.cf"文件設置不可更改位:
[root@deep]#chattr+i/etc/sendmail.cf
為"sendmail.cw"文件設置不可更改位:
[root@deep]#chattr+i/etc/sendmail.cw
為"sendmail.mc"文件設置不可更改位:
[root@deep]#chattr+i/etc/sendmail.mc
為"null.mc"文件設置不可更改位:
[root@deep]#chattr+i/etc/null.mc
為"aliases"文件設置不可更改位:
[root@deep]#chattr+i/etc/aliases
為"access"文件設置不可更改位:
[root@deep]#chattr+i/etc/mail/access
qmail安全
qmail有一個名為rcpthosts(該文件名源於RCPTTO命令)的配置文件,其決定了是否接受一個郵件。只有當一個RCPTTO命令中的接收者地址的域名存在於rcpthosts文件中時,才接受該郵件,否則就拒絕該郵件。若該文件不存在,則所有的郵件將被接受。當一個郵件伺服器不管郵件接收者和郵件接收者是誰,而是對所有郵件進行轉發(relay),則該郵件伺服器就被稱為開放轉發(openrelay)的。當qmail伺服器沒有rcpthosts時,其是開放轉發的。
設置自己伺服器為非openrelay的最簡單的辦法就是將你的郵件伺服器的所有域名(若DNS的MX記錄指向該機器,也應該包括該域名。例如你的機器有三個域名mail.linxuaid.com.cn、mail1.linuxaid.com.cn,而且linuxaid.com.cn的MX指向mail.linuxaid.com.cn,則qmail的rcphosts的應該包括mail.linuxaid.com.cn、mail1.linuxaid.com.cn和linuxaid.com.cn)。
但是這將導致你的本地客戶也被拒絕使用你的伺服器轉發郵件,而要支持客戶使用MUA來發送郵件,必須允許客戶使用伺服器轉發郵件。qmail-smtpd支持一種有選擇性的忽略rcpthosts文件的方法:若qmail-smtpd的環境變數RELAYCLIENT被設置,則rcpthost文件將被忽略,relay將被允許。但是如何識別一個郵件發送者是否是自己的客戶呢?qmail並沒有採用密碼認證的方法,而是判斷發送郵件者的源IP地址,若該IP地址屬於本地網路,則認為該發送者為自己的客戶。
這裡就要使用ucspi-tcp軟體包。在這裡我們要使用該軟體包的tcpserver程序。該程序的功能類似於inetd-監聽進入的連接請求,為要啟動的服務設置各種環境變數,然後啟動指定的服務。
tcpserver的配置文件是/etc/tcp.smtp,該文件定義了是否對某個網路設置RELAYCLIENT環境變數。例如,本地網路是地址為192.168.10.0/24的C類地址,則tcp.smtp的內容應該設置如下:
127.0.0.1:allow,RELAYCLIENT=""
192.168.10.:allow,RELAYCLIENT=""
:allow
這幾個規則的含義是指若連接來自127.0.0.1和192.168.10則允許,並且為其設置環境變數RELAYCLIENT,否則允許其他連接,但是不設置RELAYCLIENT環境變數。這樣當從其他地方到本地的25號連接將會被允許,但是由於沒有被設置環境變數,所以其連接將會被qmail-smptd所拒絕。
但是tcopserver並不直接使用/etc/tcp.smtp文件,而是需要先將該文件轉化為cbd文件:
[lix@mail/etc]$#tcprulestcp.smtp.cdbtcp.smtp.temp
然後再回頭看在/service/qmail-smtpd目錄下的run文件中有
/usr/local/bin/tcpserver-v-p-x/etc/tcp.smtp.cdb
可以看到,tcpserver利用了/etc/smtp.cbd文件。若本地有多個網路,則需要這些網路都出現在/etc/tcp.smtp文件中。
這樣就實現了允許本地客戶relay郵件,而防止relay被濫用。

應用


1
SMTP
SMTP
.本備忘錄的狀態
本備忘錄講述了一種基於CCITT的X.25標準提供的虛電路業務的SMTP標準。
本備忘錄的發布不受任何限制。
2.簡介
在RFC821("SIMPLEMAILTRANSPORTPROTOCOL",SMTP,簡單郵件傳輸協議
的附錄D中提到了直接將SMTP置於X.25虛電路(ISO第3層)上的可能性。並建議“利
用一種類似於TCP可靠的端到端協議在X.25的連接上”。在1981年時,考慮到psdns的
總體的可靠性,這毫無疑問是可行的。這一業務現在(1989年)已經非常可靠,它允許直
接將其置於虛電路業務上。
在包括22個不同的國家的24個PSDN網的許多產品,證明了這種方法是成功的,結
果證明,即使使用在一些花費比較昂貴的PSDN中,這種方法還是十分經濟的,在X.25專
網和X.25區域網中,這種方法也是成功。
每一個SMTP會話必須打開一條X.25虛電路(VirtualCircuit,VC),SMTP會話將
使用由VC提供的全雙工通道。通常,VC是由發起呼叫的一方關閉的。
3.協議ID和呼叫用戶數據
呼叫用戶數據區的前4個位元組應該是0xC0F7,0000(十六進位),十進位是19224700。
這個欄位通常用來標識一個協議ID,或者PRID。
但是在實際的操作中,應該有能力在基本前綴地址上配置呼叫用戶數據,包括協議ID
欄位。
4.數據流
在發送端通常把SMTP數據分成許多數據包,相應地,在數據包封裝的時候應該置M
位(表示有後續數據包)。數據包的總長度可以達到2048個位元組。
通常我們建議SMTP命令和響應應在一個數據包發送出去,或者只有一個後續數據包。
只要對調試協議方便即可。但這並不要求是必須的。
5.識別數據
Q比特被置位的分組和中斷分組是沒有用的。如果收到了,應該被忽略掉。
6.電路複位
如果收到了一個3層的電路複位指示,這條VC應該清除,SMTP連接應該重新建立。
重新建立會帶來一些時延,也可能是不同的呼叫業務。
7.呼叫業務
任何被X.25呼叫請求業務選擇的協商特徵都可以使用。使用時應有能力為每一個被叫
地址指定業務。
X.25使用的字元編碼是完整的8位ASCII碼,沒有任何遺漏和修改。一行應該以CRLF
(十進位:1310)結尾,也可以僅僅以LF(十進位:10)來標識一行的結束。
9.關閉連接
跟TCP協議不同,在清除請求的過程中,X.25不提供數據的同步傳送;當清除虛電
路時,就丟棄所有正在傳送的數據包。因此,當收到“服務關閉”消息時,主叫的一邊關閉
SMTP會話層(在X.25上),這種消息要麼是QUIT命令的響應,或者是因為服務必須中止。
10.超時
SMTP通常不提供超時會話,在X.25,以下幾項是有效的:
10.1呼叫請求
如果在100秒內沒有收到“呼叫接受”信息,或者在120秒(另外)內沒有收到“服
務準備好”信息,那麼應該清除這次呼叫,然後重試。
10.2已經建立的呼叫
當協議會話建立之後,在10分鐘內如果沒有收到任何響應,那麼就應該清除這條虛
電路。
10.3關閉
執行QUIT命令后,超時時間縮短為20秒。這可能會導致不經意地退出,但它不會影
響已經完成的SMTP業務。
10.4清除
當X.25“清除請求”發出時,這條虛電路將在X.25協議指定的時間內超時。
11.其他特性
X.25的其他特性,如永久虛電路和D比特的選擇,都沒有用到。

服務擴展


SMTP提供一種可靠的有效的傳送機制,它用於傳送電子郵件。雖然十幾年來,它的作用已經有目共睹,可是對它功能的擴充也是必不可少的。對SMTP服務的擴展我們介紹一下:在SMTP轉發的郵件中包括信封和內容這兩種東西。我們寫信也寫信封和信皮,我們可以借生活中的信件來幫助理解。
(1)SMTP信封比較容易理解,它被作為一系列的SMTP協議單元傳送,它包括發送者地址,傳送模式,還有一個或多個接收者地址。如果有不清楚的地方,請參閱《SMTP協議標準》。
(2)至於內容,它是由兩部分組成的,一部分是信頭,一部分是信體,信頭是由一個個的域/值對(一個域,一個值)組成的,如果信體有結構的話,它的結構是以MIME構造的。內容從根本上來說是文本的,一般也是由ASCII碼構成的,但是由於使用了MIME,所以這個限制應該也是沒有了,但信頭卻不行,一般都應該使用ASCII碼錶示。雖然SMTP協議是一個不錯的協議,可是對它的擴展還是不可避免,本文主要說明了一種擴展方法,使用這種擴展方法,伺服器和用戶之間可以相互知道對方使用了擴展,使用了多少,如果進行通信。
這裡我們希望讓大家知道網路協議中的一個經驗:參數越多,死得越快;參數越少,越能持久。參數太多了,根本不利於使用,無法推廣,早晚會被別的協議取代。這也符合科學的基礎原理,簡單。這說明在實現時一定要小心,如果不小心會便得到的遠遠小於付出的,有時根本不能提供任何益處。
下面我們看一下EHLO命令,支持SMTP服務擴展的客戶應該以EHLO命令開始SMTP會話,而不是通常的HELO命令。如果伺服器也支持,那就返回確認響應,如果不支持就返回失敗響應。因為引入了EHLO命令,因此會話開始的第一條命令可以是HELO或EHLO。
因此引入了新的參數,所以SMTP的MAILFROM和RCPTTO命令行長度也能再是512位元組了,但是引入新參數的長度必須加以說明,以便實現者準備緩衝區。
命令格式如下:
ehlo-cmd::="EHLO"SPdomainCRLF
在命令成功是,伺服器返回代碼250,如果失敗返回代碼550,如果出錯,返500,501,502,504或421。對比《SMTP協議標準》,EHLO命令可以出現在任何HELO命令出現的地方,在成功發送一個HELO或EHLO命令后再次發送它會使伺服器返回503。客戶這時不能緩存伺服器返回的任何信息。這裡一定要注意的是,每次開始SMTP擴展服務會話的時候必須發送EHLO命令。如果伺服器能夠處理EHLO命令,它會返回代碼250。這樣,伺服器和客戶就處於初始狀態了,也就是說,所有的狀態表和緩衝區已經準備完畢。通常這種響應是多行的,每行響應包括一個關鍵字,如果有的話,還有一個或多個參數,響應的語法如下:
ehlo-ok-rsp::="250"domain[SPgreeting]CRLF
/("250-"domain[SPgreeting]CRLF
*("250-"ehlo-lineCRLF)
"250"SPehlo-lineCRLF)
greeting::=1*
ehlo-line::=ehlo-keyword*(SPehlo-param)
ehlo-keyword::=(字母/數字)*(字母/數字/"-")
ehlo-param::=1*
ALPHA::=
DIGIT::=
CR::=
LF::=
SP::=
雖然EHLO關鍵字可以是大寫,小寫,大小寫混合的,但是對它的處理是大小寫敏感的,這是與原來規定不同的。IANA支持SMTP服務擴展註冊,相對於每個擴展都有一個相應的EHLO關鍵字值,每個在IANA註冊的服務擴展必須在一個RFC中定義。如果一個關鍵字以X開頭,它指的是這個服務擴展是雙方約定的,不是標準的。
如果出於某種原因,伺服器不能列出它所支持的服務擴展,就返回代碼554。在接收到這個代碼后,客戶要麼發送HELO,要麼發送QUIT命令。有時候伺服器接收到EHLO命令,可是命令參數不可接受,它就返回代碼501。如果伺服器識別了EHLO,但對伺服器擴展未實現,則返回代碼502。
如果伺服器不再提供服務擴展,則返回代碼421。在接收到這個代碼后,客戶要麼發送HELO,要麼發送QUIT命令。如果伺服器不支持服務擴展,則返回500,伺服器保持現有狀態,在接收到這個代碼后,客戶要麼發送HELO,要麼發送QUIT命令。
有時候,SMTP伺服器會在接收到EHLO命令后因為某種原因關閉連接,這種情況在原來的SMTP協議標準中未涉及。為了處理這種情況,客戶必須能夠確認伺服器是否能夠工作,它可以重新連接併發送HELO或EHLO命令。有些伺服器在接收到一個EHLO命令後會拒絕接收新的HELO命令,這時可以利用RSET命令重新啟動,然後再發送HELO。如果客戶不注意這樣的小細節,會收到失敗代碼。
下面我們來看一下MAILFROM和RCPTTO參數。許多服務擴展是在MAILFROM和RCPTTO命令后加入一些參數來實現的。下面我們看一下這兩個命令的格式:
esmtp-cmd::=inner-esmtp-cmd[SPesmtp-parameters]CRLF
esmtp-parameters::=esmtp-parameter*(SPesmtp-parameter)
esmtp-parameter::=esmtp-keyword["="esmtp-value]
esmtp-keyword::=(字母/數字)*(字母/數字/"-")
esmtp-value::=1*
inner-esmtp-cmd::=("MAILFROM:"返迴路徑)/("RCPTTO:"轉發路徑)
如果伺服器不能識別或實現一個或多個MAILFROM或RCPTTO參數,它應該返回代碼555。如果這種情況只是暫時的,伺服器返回代碼455。其它返回代碼請查閱相關資料,這裡不再詳述了。伺服器以服務擴展處理時,它處理的任何信息都應該在包頭上加上“服務擴展標記”以示區別。
下面是一個例子:
(1)雙方交互:S是伺服器,C是客戶。
S:
C:
S:220dbc.mtview.ca.usSMTPserviceready
C:EHLOymir.claremont.edu
S:250dbc.mtview.ca.ussayshello
...
(2)下面也是一個例子:
S:
C:
S:220dbc.mtview.ca.usSMTPserviceready
C:EHLOymir.claremont.edu
S:250-dbc.mtview.ca.ussayshello
S:250-EXPN
S:250-HELP
S:250-8BITMIME
S:250-XONE
S:250XVRB
...
這說明伺服器實現了服務擴展EXPN和HELP,這兩個是標準的服務擴展,另外兩個以X開頭的是非標準的。
SMTP
SMTP
(3)最後,我們來看看伺服器不支持服務擴展時的情況:
S:
C:
S:220dbc.mtview.ca.usSMTPserviceready
C:EHLOymir.claremont.edu
S:500Commandnotrecognized:EHLO
...
代碼500表示伺服器不支持服務擴展。
  • 目錄