對(duì)任何重要的 P2P 應(yīng)用程序而言,對(duì)等機(jī)之間的安全通信都是一個(gè)核心要求。盡管安全的細(xì)節(jié)依賴于如何使用該應(yīng)用程序和該應(yīng)用程序?qū)⒁Wo(hù)什么,但通過使用現(xiàn)有技術(shù),例如 SSL 實(shí)現(xiàn)強(qiáng)壯的、一般用途的安全通常是可能的。本月,Todd Sundsted 演示如何在 P2P 安全中使用 SSL(通過 JSSE)。
我們考察了 p2p 應(yīng)用程序中的信任角色。信任的等級(jí)是衡量我們確信程度的尺度,即我們正與之通信的人是否是我們以為的那個(gè)人,以及我們正訪問的資源是否是我們以為的那些。我們也研究了用于在所有分布式應(yīng)用程序,包括 p2p 應(yīng)用程序中建立信任的三個(gè)構(gòu)件:認(rèn)證、授權(quán)和加密。
現(xiàn)在我們將通過修改我們的簡單 p2p 應(yīng)用程序把上個(gè)月的課程應(yīng)用到實(shí)踐中。特別地,我們將用 X.509 證書擴(kuò)展該應(yīng)用以支持 P2P 認(rèn)證和加密。我們將在將來的文章中處理授權(quán)問題。
安全認(rèn)證
一個(gè)應(yīng)用程序的安全需求在很大程度上依賴于將如何使用該應(yīng)用程序和該應(yīng)用程序?qū)⒁Wo(hù)什么。不過,用現(xiàn)有技術(shù)實(shí)現(xiàn)強(qiáng)大的、一般用途的安全通常是可能的。認(rèn)證就是一個(gè)很好的示例。
當(dāng)顧客想從 Web 站點(diǎn)購買某個(gè)產(chǎn)品時(shí),顧客和 Web 站點(diǎn)都要進(jìn)行認(rèn)證。顧客通常是以提供名字和密碼的方式來認(rèn)證他自己。另一方面,Web 站點(diǎn)通過交換一塊簽名數(shù)據(jù)和一個(gè)有效的 X.509 證書(作為 SSL 握手的一部分)來認(rèn)證它自己。顧客的瀏覽器驗(yàn)證該證書并用所附的公用密鑰驗(yàn)證簽名數(shù)據(jù)。一旦雙方都認(rèn)證了,則交易就可以開始了。
SSL 能用相同的機(jī)制處理服務(wù)器認(rèn)證(就如在上面的示例中)和客戶機(jī)認(rèn)證。Web 站點(diǎn)典型地對(duì)客戶機(jī)認(rèn)證不依賴 SSL ― 要求用戶提供密碼是較容易的。而 SSL 客戶機(jī)和服務(wù)器認(rèn)證對(duì)于透明認(rèn)證是完美的,對(duì)等機(jī) ― 如 p2p 應(yīng)用程序中的對(duì)等機(jī)之間一定會(huì)發(fā)生透明認(rèn)證。
安全套接字層(Secure Sockets Layer(SSL)) SSL 是一種安全協(xié)議,它為網(wǎng)絡(luò)(例如因特網(wǎng))的通信提供私密性。SSL 使應(yīng)用程序在通信時(shí)不用擔(dān)心被竊聽和篡改。
SSL 實(shí)際上是共同工作的兩個(gè)協(xié)議:“SSL 記錄協(xié)議”(SSL Record Protocol)和“SSL 握手協(xié)議”(SSL Handshake Protocol)。“SSL 記錄協(xié)議”是兩個(gè)協(xié)議中較低級(jí)別的協(xié)議,它為較高級(jí)別的協(xié)議,例如 SSL 握手協(xié)議對(duì)數(shù)據(jù)的變長的記錄進(jìn)行加密和解密。SSL 握手協(xié)議處理應(yīng)用程序憑證的交換和驗(yàn)證。
當(dāng)一個(gè)應(yīng)用程序(客戶機(jī))想和另一個(gè)應(yīng)用程序(服務(wù)器)通信時(shí),客戶機(jī)打開一個(gè)與服務(wù)器相連接的套接字連接。然后,客戶機(jī)和服務(wù)器對(duì)安全連接進(jìn)行協(xié)商。作為協(xié)商的一部分,服務(wù)器向客戶機(jī)作自我認(rèn)證。客戶機(jī)可以選擇向服務(wù)器作或不作自我認(rèn)證。一旦完成了認(rèn)證并且建立了安全連接,則兩個(gè)應(yīng)用程序就可以安全地進(jìn)行通信。按照慣例,我將把發(fā)起該通信的對(duì)等機(jī)看作客戶機(jī),另一個(gè)對(duì)等機(jī)則看作服務(wù)器,不管連接之后它們充當(dāng)什么角色。
在 Java 應(yīng)用程序如何使用 SSL
用于 Java 應(yīng)用程序的 SSL 由“Java 安全套接字?jǐn)U展”(Java Secure Socket Extension(JSSE))提供。JSSE 是最近發(fā)布的 JDK 1.4 Beta 測試版的一個(gè)標(biāo)準(zhǔn)部件,但對(duì)早些版本的 Java 平臺(tái)它是作為一個(gè)擴(kuò)展可用的。
JSSE 用 SSL 作它的安全套接字的底層機(jī)制。JSSE 安全套接字除了支持透明認(rèn)證和加密之外,其工作方式與常規(guī)套接字相似。因?yàn)樗鼈兛雌饋硪才c普通套接字(它們是類 和類 的子類)相似,所以使用 JSSE 的多數(shù)代碼不用修改。受到影響最多的代碼是那些處理安全套接字工廠(secure socket factory)的創(chuàng)建和初始化的代碼。
如果您想在早于版本 1.4 的 Java 平臺(tái)中使用 JSSE,那么您將不得不自己去下載并安裝 JSSE 擴(kuò)展。安裝說明非常簡單,所以我不想在這里重復(fù)。
模型
圖 1 說明在對(duì)等機(jī)之間的通信中 SSL 將充當(dāng)?shù)慕巧?/p>
名為 A 和 B 的兩臺(tái)對(duì)等機(jī)想安全地進(jìn)行通信。 在我們簡單的 p2p 應(yīng)用程序的環(huán)境中,對(duì)等機(jī) A 想查詢對(duì)等機(jī) B 上的一個(gè)資源。
每個(gè)對(duì)等機(jī)都有包含其專用密鑰的一個(gè)數(shù)據(jù)庫(名為 keystore)和包含其公用密鑰的證書。密碼保護(hù)數(shù)據(jù)庫的內(nèi)容。該數(shù)據(jù)庫還包含一個(gè)或多個(gè)來自被信任的對(duì)等機(jī)的自簽名證書。
對(duì)等機(jī) A 發(fā)起這項(xiàng)事務(wù),每臺(tái)對(duì)等機(jī)相互認(rèn)證,兩臺(tái)對(duì)等機(jī)協(xié)商采用的密碼及其長度并建立一個(gè)安全通道。完成這些操作之后,每個(gè)對(duì)等機(jī)都知道它正在跟誰交談并且知道通道是安全的。
初始化
因?yàn)?JSSE 和 SSL 的介紹對(duì)初始化代碼有很大影響,所以讓我們來考察對(duì)等機(jī) A 中負(fù)責(zé)初始化的代碼。
|
當(dāng)用戶第一次啟動(dòng)應(yīng)用程序時(shí),應(yīng)用程序提示輸入一個(gè)身份(別名)和一個(gè)密碼。身份只用于對(duì)對(duì)等機(jī)進(jìn)行本地識(shí)別 ― 它沒有全局意義。應(yīng)用程序生成一個(gè)隨機(jī)的 128 位(16 字節(jié))的字符串,應(yīng)用程序用這個(gè)字符串對(duì)對(duì)等機(jī)進(jìn)行全局識(shí)別并將它轉(zhuǎn)換成字母數(shù)字字符串。應(yīng)用程序用身份、密碼和名字創(chuàng)建 keystore 和公開/專用密鑰對(duì),密鑰對(duì)存儲(chǔ)在 keystore 中。密碼保護(hù) keystore 中的信息。
我確信您已經(jīng)注意到我創(chuàng)建初始 keystore 時(shí)采取的辦法。應(yīng)用程序把 keytool 啟動(dòng)為一個(gè)外部進(jìn)程,keytool 創(chuàng)建 keystore。我不得不這樣做,因?yàn)楣驳?Java 安全 API 不提供創(chuàng)建證書的工具 ― 這些功能隱藏在 JSSE 中,它的 API 未發(fā)布。啟動(dòng) keytool 來創(chuàng)建 keystore 的最大缺點(diǎn)是要冒用戶提供的密碼被公開的風(fēng)險(xiǎn),用戶提供的密碼作為參數(shù)列表的一部分被傳遞進(jìn)去。
應(yīng)用程序創(chuàng)建了 keystore 之后,就打開 keystore 并將它裝入內(nèi)存(如果我們已經(jīng)能夠直接創(chuàng)建 keystore,則我們就可以免去這一步驟)。應(yīng)用程序從 keystore 創(chuàng)建一個(gè) 密鑰管理器(key manager)和一個(gè) 信任管理器(trust manager)。密鑰管理器管理密鑰,這些密鑰用于在安全套接字對(duì)面相對(duì)應(yīng)用程序的對(duì)等機(jī)來認(rèn)證它。信任管理器管理證書,這些證書用于對(duì)位于安全套接字另一端的對(duì)等機(jī)進(jìn)行認(rèn)證。
最后,應(yīng)用程序創(chuàng)建一個(gè) 實(shí)例,這個(gè)實(shí)例充當(dāng)安全套接字工廠的工廠。應(yīng)用程序創(chuàng)建 和 類的安全版本并將它們用于稍后的通信。
用戶界面
余下代碼的大部分跟我們的前發(fā)行版是相同的。這是 JSSE 帶來的好處之一 ― 用 JSSE 創(chuàng)建的安全套接字看起來和常規(guī)套接字相似,工作起來也和常規(guī)套接字相似。支持代碼也沒什么不同(除了創(chuàng)建和初始化代碼必須修改外)。然而,還是有和用戶界面有關(guān)的改動(dòng)。大部分這些改動(dòng)是受到了我想讓這個(gè)應(yīng)用程序?qū)δ切┲幌肟焖俚卦O(shè)置這個(gè)應(yīng)用程序來試驗(yàn)的愿望而激發(fā)的。
作為對(duì)讀者反饋的回應(yīng),我改善了命令行界面。對(duì)等機(jī)及其資源存在于一個(gè)層次結(jié)構(gòu)中,用戶用命令 ls和 cd訪問這個(gè)結(jié)構(gòu)。 ls 命令列出層次結(jié)構(gòu)中某個(gè)特定點(diǎn)的內(nèi)容(與 UNIX 的 ls 命令或 DOS 的 dir命令所做的相似), cd 命令改變層次結(jié)構(gòu)中的當(dāng)前位置(再一次與 UNIX 和 DOS 中的同名命令相似)。 cd ..用于在層次結(jié)構(gòu)中進(jìn)行回退。
為使應(yīng)用程序更容易使用,我已經(jīng)創(chuàng)建了兩個(gè) zip 文件,每一個(gè)都包含該應(yīng)用程序的一個(gè)已經(jīng)適當(dāng)配置了的實(shí)例。一個(gè)實(shí)例在端口 7776 進(jìn)行通信,另一個(gè)在端口 7777。它們也都已被配置成彼此認(rèn)證,為的是能夠建立安全通道。這些 zip 文件的名稱為 peerA.zip 和 peerB.zip。“自述文件”(README)提供了更多詳細(xì)的使用說明。
結(jié)束語
在 p2p 應(yīng)用程序中加入 SSL 是提供簡單卻強(qiáng)大的安全的極好辦法。我們將繼續(xù)我們的 P2P 之旅,考察更成熟的對(duì)等機(jī)發(fā)現(xiàn)方法。


