編輯:關於Android編程
原文地址:Mina SSLFilter(Apahce Mina user guide Chapter11 SSL Filter)
SslFilter過濾器是負責管理數據的加密和解密通過安全連接。每當你需要建立一個安全連接,或將現有的連接使它安全,你必須添加SslFilter過濾器鏈。
任何會話可以修改它的信息過濾器鏈,它允許使用協議像startTLS打開連接。
請注意,雖然這個名字包括SSL,SslFilter支持TLS。實際上,TLS已經支持取代SSL,但是由於歷史原因,SSL仍然廣泛使用。
如果你想讓你的應用程序支持SSL / TLS,只需添加的SslFilter鏈:
... DefaultIoFilterChainBuilder chain = acceptor.getFilterChain(); SslFilter sslFilter = new SslFilter(sslContext); chain.addFirst("sslFilter", sslFilter); ...你當然也需要一個SslContext實例:
SSLContext sslContext; try { // Initialize the SSLContext to work with our key managers. sslContext = SSLContext.getInstance( "TLS" ); sslContext.init( ... ); // Provide the needed KeyManager[], TrustManager[] and SecureRandom instances } catch ( Exception e ) { // Handle your exception }這取決於你提供的KeyManager,TrustManager和SecureRandom實例。
確保注入SslFilter到過濾器鏈中的第一的位置!
稍後我們將看到如何創建一個SSLContext詳細為例。
如果你想要更深入地理解它是如何工作的,請閱讀下面的段落…
我們不打算解釋SSL是如何工作的,在此之外有非常好的書。我們將給一個快速介紹它是如何工作的,以及它是如何在Mina中實現的。
首先,你必須明白SSL / TLS協議中定義的RFCs:TLS 1.0, TLS 1.1和TLS 1.2,這裡有關於TLS 1.3的介紹。
在成為TLS之前,它最初是由Netscape命名為SSL(從1.0到3.0)。如今,SSL 2.0 * 3.0和SSL * *已經棄用並且不應該被使用了。
因為它是一個協議,它需要客戶端和服務器之間的一些會話。這是所有的SSL / TLS是什麼:關於描述該會話。
這足以知道任何保證交換排除是一個過程階段,叫做握手,它的角色是客戶端和服務器之間達成協議將加密方法來使用。一個基本的SSL / TLS會話將會看起來像下面這樣:
正如你所看到的這張照片,這是一個2階段協議:第一次握手,然後完成客戶端和服務器將能夠交換數據加密。
一般地,它是關於談判階段許多元素將用於加密數據。在本文的上下文中細節不是很有趣的,足夠說許多消息是客戶機和服務器之間交換,並且沒有數據可以發送在這個階段。
實際上,握手開始有兩個條件:服務器必須等待一些握手消息到達,客戶端必須發送ClientHello消息。
我們使用Java SSLEngine類來管理整個SSL / TLS協議。Mina應該關注的現狀是會話,這樣它將能夠獲取和處理客戶端HelloClient消息。當你在過濾器鏈中注入SslFilter,有幾件事發生:
創建SslHandler實例(我們每個會話創建一個實例)。這個SslHandler實例負責整個處理(握手和即將到來的消息的加密/解密)。SslHandler使用SslContext實例創建一個SSLEngine,已附加到SslFilter。SslEngine被實例配置和初始化。SslHandler實例存儲到Session會話中。除非特殊需要,我們發起握手(有不同的含義在客戶端和服務器端,客戶端將發送ClientHello消息,而服務器切換到一個模式,它等待一些數據打開)。注意握手初始化以後可以做,如果需要的話。
我們都是set。接下來的幾個步驟是純粹的SSL / TLS協議交換。如果session.write()方法被調用時,該消息將被排隊等待握手完成。任何等待消息當時SslFilter添加到鏈會導致SSL / TLS握手失敗,所以當你想注入時確保你有一個干淨的地方。我們也不會收到任何消息,這並不是一個SSL / TLS協議消息。
最後一點很重要,如果你想實現StartTLS:因為它允許您的應用程序在任何時候切換,從一個純文本交換加密交換,你要確保兩側沒有等待消息。顯然,在客戶端——啟動StartTLS——每個等待消息已被發送,在StartTLS可以發送消息之前,但它必須阻止任何其他信息,不屬於以下握手,直到完成握手。在服務器端,一旦StartTLS消息已經收到,沒有消息應該寫入遠程對等。
事實上,注入鏈中的SslFilter應該阻止任何交換不握手協議的一部分,直到握手完成。如果你提交一個消息發送和加密前的握手已經完成,消息不會被拒絕,但在握手已完成時會加入隊列並處理。
在此之後,每個發送的消息將會通過SslHandler實例被加密,和每條消息收到必須通過SslHandler完全解密,然後提供給下一個過濾器。
好,握手已完成。你的SslFilter准備好處理傳入和傳出消息。讓我們聚焦那些你要寫的session會話。
一個重要的事情是你可以寫多個消息在同一session會話(如果你有一個Executor鏈)。問題在於SSLEngine不能夠處理多個消息。我們需要序列化消息被寫入。更糟糕的是:你不能處理傳入消息,並在同一時間傳出消息。
總而言之,SSL / TLS處理就像一個黑盒,只接受一個輸入並且無法處理任何東西,直到它完成了它的任務。以下為傳出消息模式代表了它的工作方式。
這與傳入消息沒什麼不同,除了我們之間不會有一個Executor的IoProcessor和SslFilter。這讓事情變得更簡單,除了一個重要的事情發生:當我們處理傳入消息的時候,我們不能處理輸出消息。請注意,它還適用於反過來:當一個即將離任的消息被處理,我們不能處理傳入消息:
注意:重要的是SslHander無法處理超過一個消息。
現在,我們將深入一點,深入Mina代碼。我們將涵蓋所有過濾器操作:
·Managementoinit()odestroy()oonPreAdd(IoFilterChain, String, NextFilter)oonPostAdd(IoFilterChain, String, NextFilter)oonPreRemove(IoFilterChain, String, NextFilter)oonPostRemove(IoFilterChain, String, NextFilter)·Session eventsosessionCreated(NextFilter, IoSession)osessionOpened(NextFilter, IoSession)osessionClosed(NextFilter, IoSession)osessionIdle(NextFilter, IoSession, IdleStatus)oexceptionCaught(NextFilter, IoSession, Throwable)ofilterClose(NextFilter, IoSession)oinputClosed(NextFilter, IoSession)·Messages eventsomessageReceived(NextFilter, IoSession, Object)ofilterWrite(NextFilter, IoSession, WriteRequest)omessageSent(NextFilter, IoSession, WriteRequest)
這裡有過濾器的管理方法:
這就是我們創建SslHandler實例,並初始化它。我們還定義了支持密碼。
SslHandler實例將本身創建一個SSLEngine的實例,並配置SslFilter它所有的參數設置:
如果這是客戶端或服務器端在服務器端,國旗,表示我們想要或需要客戶端身份驗證啟用密碼的列表協議列表當它完成的時候,這個實例的引用會存儲在session會話的屬性。
如果不影響推遲,這就是我們開始握手的地方。這就是這個方法要做的。所有的邏輯是由SslHandler實現。
在這裡,我們停止SSL會話並清理會話(從會話的屬性中刪除過濾器從會話的鏈和SslHandler實例)。在刷新了任何尚未處理的事件之後,Sslhandler實例也要被銷毀。
這裡有事件傳播,通過SslFilter過濾器鏈並處理:
我們只是銷毀SslHandler實例。
我們有一個特殊的任務進行異常,由於關閉session會話引起:我們必須收集所有的消息回答epending將它們添加到異常傳播。
在這裡,如果有一個SSL會話開始,我們需要關閉它。在任何情況下,我們傳播事件鏈到下一個過濾器。
最後,同樣重要的是,這三個事件相對於消息:
當我們從套接字讀取一些數據時,收到這個事件。我們必須照顧一些角落情況:已完成握手。握手已經啟動但仍未完成*沒有握手開始,和SslHandler尚未初始化。
根據頻率列出這三個用例的順序。讓我們看看會發生什麼對這些用例。
好!這意味著每一個傳入消息封裝在一個SSL / TLS信封,而且應該解密。現在,我們討論的是關於消息的,但我們實際上收到字節,可能需要進行聚合,以形成完整的信息(至少在TCP)。如果消息是支離破碎的,我們會收到許多緩沖區,當我們將收到最後一塊時我們將能夠完全解密它。記住,我們阻塞了所有的處理,它可以對這次session會話阻塞SslHandler實例很長一段時間……
在任何情況下,每個數據塊都是由SslHandler處理,它代表SslEngine解密接收的字節。
這是我們已經實現的基本算法messageReceived():
get the session's sslHandler
syncrhonized on sshHandler {
if handshake completed
then
get the sslHandler decrypting the data
if the application buffer is completed, push it into the message to forward to the IoHandler
else
enqueue the incoming data}
flush the messages if any
這裡的重要部分是SslHandler將累積數據,直到有一個完整的消息進入鏈。這可能需要一段時間,並且有許多套接字讀取。原因是SSLEngine無法處理消息,除非它有所有字節符合完全解碼的信息。
提示:增加傳輸緩沖區大小限制往返需要的數量來發送一個大消息。
意味著收到消息是握手協議的一部分。沒有將傳播到IoHandler,消息將被SslHandler消費。
直到完成完整的握手,每個傳入的數據將被視為一個握手規范消息。
同時,消息IoHandler將加入隊列,等待握手完成。
這是一個模式代表完整的過程,當數據在兩個傳送接收:
這個事件處理時IoSession.write()方法被調用。
如果SSLsession會話沒有開始,我們只是積累寫的消息。它將在稍後發送。
在這裡有一個棘手的參數,對於一些非常具體的需要。通常,當實現startTLS協議,服務器切換從一個非安全連接到一個安全連接的意思是一個應用程序消息(和潛在的響應),我們需要響應發送回客戶機之前SslFilter安裝(否則,響應將被阻塞,etablishement安全連接會失敗)。這是DISABLE_ENCRYPTION_ONCE屬性。它包含什麼都無所謂(它可以是一個布爾值),這是足夠的為這個參數在會話第一消息bypasse SslFilter。
我們控制在會話的屬性中存在DISABLE_ENCRYPTION_ONCE標識,並且如果存在,我們將它從session會話中移除,並且推送消息進入消息隊列被發送。
此外,如果握手還沒有完成,我們保持消息隊列中,如果完成,我們加密和調度寫。
如果已經安排寫一些消息,我們就釋放。
在這裡,它只是一種回到未加密的IoHandler消息傳播。
我們看到,為了建立SSL會話,我們需要創建一個SSLContext。這是代碼:
SSLContext sslContext; try{ // Initialize the SSLContext to work with our key managers. sslContext = SSLContext.getInstance( "TLS" ); sslContext.init( ... ); // Provide the needed KeyManager[], TrustManager[] and SecureRandom instances }catch ( Exception e ){ // Handle your exception }
我們沒有暴露的是構造函數和init()方法。
SSLContext可以影響——通過其構造函數創建,或者我們讓靜態工廠返回一個實例(這是我們所做的在前面的代碼。第二種方法非常簡單,適合大多數時候。這足以通過使用協議的名稱,這是:
·SSL·SSLv2·SSLv3·TLS·TLSv1·TLSv1.1·TLSv1.2(not supported in Java 6)這裡強烈建議選擇更高的算法(即TLSv1.2)如果你的客戶支持它。
init()方法接受3個參數:
·a KeyManager(can be null)·a TrustManager(can be null)·a random generator (can be null)如果參數被設置為null,安裝安全提供者會選擇優先級最高的實現。
最近在做一個多語言切換的功能,類似於微信的語言切換,搜了下資料基本上都是以下這種:1. 實現的效果 和微信類似,在設置界面打開切換語言的界面,選擇語言後重啟 H
1.MyDatabaseHelper.java代碼如下: package org.lxh.demo; import android.content.Context; i
5、Activity用SharedPreferences保存數據,大小有木有限制?個人理解:SharedPreferences是哪種存儲數據的方式竟然記不清楚了,個人印象
android開發中通過View的getDrawingCache方法可以達到截屏的目的,只是缺少狀態欄!原始界面截屏得到的圖片代碼實現1. 添加權限(AndroidMan