我正在研究SSL web server using NIO and the SSLEngine。我能够成功处理握手并发送/接收应用程序数据。但是,我很难理解如何维护SSL会话状态。
我正在使用Firefox 10来测试我的网络服务器。在初始页面加载时,一切都很好。握手成功完成。服务器处理客户端请求并发回响应。响应干净利落,浏览器加载应用程序数据(html,图像等)。这是从客户端发送到服务器的消息的快照。
页面请求#1
===============================================
== Message 1
===============================================
Client Request:
handshake (22)
- client_hello (1)
Server Response:
handshake (22)
- server_hello (2)
- certificate (11)
- server_key_exchange (12)
- certificate_request (13)
- server_hello_done (14)
===============================================
== Message 2
===============================================
Client Request:
handshake (22)
- certificate (11)
- client_key_exchange (16)
change_cipher_spec (20)
- client_hello (1)
handshake (22)
*** Encrypted Message ****
===============================================
== Message 3
===============================================
Client Request:
application_data (23)
*** Encrypted Message ****
application_data (23)
*** Encrypted Message ****
Server Response:
application_data (23)
*** Encrypted Message ****
同样,在初始页面加载时,一切都很好。但是,如果我刷新浏览器或转到另一个“页面”,Firefox会发送应用程序记录而不是客户端问候。
页面请求#2
===============================================
== Application Data
===============================================
Client Request:
application_data (23)
*** Encrypted Message ****
在这种情况下,SSLEngine在尝试解包应用程序数据时会抛出异常。
javax.net.ssl.SSLException: Unrecognized SSL message, plaintext connection?
我相信这是因为我在每个页面请求中实例化一个新的SSLEngine。如果我只将SSLEngine实例化一次并使其成为全局/静态变量,它会成功解包应用程序记录,并且我可以将响应发送回客户端。我可以刷新页面,访问其他页面等,没有任何问题。页面加载非常快,因为我们正在跳过整个ssl握手过程。
不幸的是,如果我在所有这些情况下(例如IE或Safari)从其他浏览器点击Web服务器,则SSLEngine内部的会话状态会被清除,我的Web服务器无法响应任何新的SSL请求。因此,实例化SSLEngine一次并使其成为全局可访问的静态变量似乎不是一个可行的选择。所以......
我该如何回应第二页请求(Page Request#2)?有没有办法将第二页请求(页面请求#2)与IP地址以外的初始握手请求(页面请求#1)联系起来?是否在第二页请求(页面请求#2)中的应用程序数据中隐藏了SSL会话ID?
提前致谢!
答案 0 :(得分:3)
您必须按SSLEngine
实例化新的SocketChannel
,而不是按请求,每页或每个应用实例化。 SSLEngine
一次只知道一个SSL连接的状态。