如何在SSL內(nèi)加密添加任意TCP連接

在大多數(shù)開(kāi)發(fā)環(huán)境中,并不是在產(chǎn)品的整個(gè)生命周期中都考慮安全性而是在出現(xiàn)安全性問(wèn)題后才采取補(bǔ)救措施。但是采取措施并不一定很可靠。例如可以寫(xiě)一段代碼,建立網(wǎng)絡(luò)連接,然后連接到一個(gè)庫(kù) — 該庫(kù)用執(zhí)行加密和認(rèn)證的版本代替所有的傳統(tǒng)網(wǎng)絡(luò)調(diào)用。實(shí)際上,這種集成的容易性是安全套接字層,或稱為 SSL(用于 secure HTTP 連接的協(xié)議)的最初目的之一。SSL 的幾種實(shí)現(xiàn)已經(jīng)在試圖順便替代標(biāo)準(zhǔn) Berkeley UNIX socket API,或者帶有盡可能相似接口的庫(kù)。

OpenSSL 庫(kù)(請(qǐng)參閱參考資料)是嘗試后一種方法的一個(gè)很好的示例。在 OpenSSL 庫(kù)中,相似的 API 模仿傳統(tǒng)的套接字調(diào)用,使用 SSL 上下文對(duì)象代替文件描述符。例如,傳統(tǒng)的寫(xiě)入套接字的調(diào)用具有以下特征:

/* Returns the number of characters successfully written */

size_t write(int file_descriptor, void *buf, size_t len)

OpenSSL 更改每個(gè)參數(shù)的類(lèi)型,但每個(gè)參數(shù)的語(yǔ)義不變:

/* Returns the number of characters successfully written */

int SSL_write(SSL *socket_info, char *buf, int len)

實(shí)際上,除 SSL 對(duì)象之外,其它所有的類(lèi)型與初始調(diào)用都是兼容的。理想情況下,開(kāi)發(fā)者能夠?qū)Τ绦蜻M(jìn)行較小的修改,只需添加一些代碼從文件描述符初始化 SSL 上下文即可。而事實(shí)上,SSL 庫(kù)都不容易使用。例如,開(kāi)發(fā)者要寫(xiě)許多附加代碼才能使 OpenSSL 在多線程環(huán)境下工作。實(shí)際上,為將這個(gè)庫(kù)集成到代碼中去,大多數(shù)開(kāi)發(fā)組織花費(fèi)的精力都比他們預(yù)計(jì)的要多的多,而結(jié)果還常常是一片混亂。

如何在SSL內(nèi)加密添加任意TCP連接

幸運(yùn)的是,有一種方法可以將加密功能無(wú)縫添加到網(wǎng)絡(luò)連接中,而不會(huì)將您原來(lái)的代碼段基址搞亂。Stunnel 是一個(gè)程序,可以使用 OpenSSL 庫(kù)對(duì)任意 TCP 會(huì)話進(jìn)行加密。它作為服務(wù)器運(yùn)行在程序外部。Stunnel 服務(wù)器主要執(zhí)行兩個(gè)功能:一,首先,接收未加密的數(shù)據(jù)流,進(jìn)行 SSL 加密,然后將其通過(guò)網(wǎng)絡(luò)發(fā)送;二,對(duì)已進(jìn)行 SSL 加密的數(shù)據(jù)流進(jìn)行解密,并將其通過(guò)網(wǎng)絡(luò)發(fā)送給另一個(gè)程序(該程序通常駐留在同一機(jī)器上,以避免本地網(wǎng)絡(luò)上的窺探攻擊)。這樣,在必要時(shí),您就可以很容易地運(yùn)行未加密的程序,當(dāng)您想要“嗅探”網(wǎng)絡(luò),看看到底有什么東西正在通過(guò)網(wǎng)絡(luò)時(shí),這一點(diǎn)很有用。

即使您是一個(gè)系統(tǒng)管理員,而不是一個(gè)開(kāi)發(fā)者,Stunnel 對(duì)您來(lái)說(shuō)也是一個(gè)強(qiáng)大的武器,因?yàn)樗梢韵虿粏⒂?SSL 的服務(wù)器端軟件添加 SSL。例如,我已經(jīng)使用 Stunnel 來(lái)保護(hù) POP、SMTP 和 IMAP 服務(wù)器。唯一不太盡人意的地方是要使用這些服務(wù)器的安全版本,客戶機(jī)必須是可識(shí)別 SSL 的。Stunnel 要求已經(jīng)安裝了 OpenSSL。它已被移植到了 Windows,以及大多數(shù) UNIX 平臺(tái)。一旦安裝了 Stunnel,用它來(lái)保護(hù)服務(wù)器就很輕松。例如,您可以通過(guò)將常規(guī)服務(wù)綁定到本地主機(jī)使 IMAP 服務(wù)器啟用 SSL,然后在外部 IP 地址(假設(shè) IMAP 服務(wù)器已經(jīng)在運(yùn)行,且外部地址為 192.168.100.1)運(yùn)行 Stunnel:

stunnel -d 192.168.100.1:imap2 -r 127.0.0.1:imap2

-d 標(biāo)志指定我們希望用來(lái)運(yùn)行自己的安全服務(wù)的端口。imap2 字符串指定使用標(biāo)準(zhǔn) IMAP 端口;我們也可以將其設(shè)為 143。Stunnel 檢查 "/etc/services" 文件以便將符號(hào)名映射到端口號(hào)。并非所有的機(jī)器都擁有這個(gè)文件(有些機(jī)器并不列出所有的標(biāo)準(zhǔn)服務(wù)),所以使用數(shù)字比使用服務(wù)名更方便。

-r 標(biāo)志指定未加密的 IMAP 服務(wù)器運(yùn)行所在的端口。

這個(gè)解決方案要求您的 IMAP 服務(wù)器只在回送(loopback)接口上偵聽(tīng)。如果 IMAP 服務(wù)器綁定到 IP 地址“0.0.0.0”,那么它將偵聽(tīng)機(jī)器上每個(gè) IP 地址上的信息,包括 192.168.100.1;這會(huì)導(dǎo)致出現(xiàn)一條出錯(cuò)消息,指出我們的安全服務(wù)端口已在使用中。大多數(shù)服務(wù)都可以配置為只綁定到一個(gè)接口。不然的話,可能要更改一行代碼。

另外,您可以將一個(gè)未加密的服務(wù)器設(shè)在一個(gè)非標(biāo)準(zhǔn)端口上。例如,您可以在端口 1143 上運(yùn)行 IMAP,然后將安全的 IMAP 數(shù)據(jù)流轉(zhuǎn)發(fā)到該端口。一般情況下,您不希望其它機(jī)器上的用戶訪問(wèn)您未加密的服務(wù)。運(yùn)行服務(wù)的機(jī)器上的個(gè)人防火墻可以加強(qiáng)這種策略。

使用 Stunnel 來(lái)保護(hù)如 IMAP 等服務(wù)面臨的一個(gè)問(wèn)題是服務(wù)器只接收來(lái)自我們提供的 Stunnel 服務(wù)器的連接。因此,所有的連接都看起來(lái)好象是來(lái)自本地機(jī)器。在 Linux 上,可以通過(guò)傳遞 -T 標(biāo)志避開(kāi)這個(gè)問(wèn)題,傳遞 -T 標(biāo)志可以使 Stunnel 服務(wù)器透明地代理信息包,這樣真正的服務(wù)器就可以得到接收到的所有信息包中的正確的源地址。

安全性問(wèn)題要比我們想象的困難的多。理想情況是,我們單擊一下按鈕就可保證自己的應(yīng)用程序安全。在對(duì)網(wǎng)絡(luò)連接加密時(shí),值得稱贊的是 Stunnel 接近了“單擊 — 安全”的理想境界,允許我們向在其它方面已經(jīng)完整的應(yīng)用程序添加安全性。不幸的是,Stunnel 有一些局限性。在服務(wù)器端,它當(dāng)前只能夠透明地代理 Linux 客戶機(jī)。在客戶機(jī)端,不容易執(zhí)行充分的證書(shū)驗(yàn)證。

盡管如此,Stunnel 仍是實(shí)用價(jià)值很高的實(shí)用程序,應(yīng)該成為程序員,同樣也是系統(tǒng)管理員的看家法寶。如果您正在開(kāi)發(fā)自己的軟件,應(yīng)該能夠很容易地將 Stunnel 集成到程序中。服務(wù)器代碼不需修改,使用本文中提供的框架通常可以很容易地對(duì)客戶機(jī)代碼進(jìn)行改寫(xiě)。