從HTTP到HTTPS協議系統升級總結
由於客戶的一個安全性要求,需要把系統從HTTP升級到HTTPS協議,以前的系統是在B/S模式Websocket體系下進行實施的,並且所有的程式碼都是基於windows本身的IOCP(非同步IO)的方式,在做專案之前本人Web端的小白一個,只懂一點C/S模式的socket,由於專案其他的人太忙了,而我又比較閒,然而就被趕鴨子上架了,於是就承擔了整個系統的升級改造;經過了大約一個多星期的調查和設施,初步的瞭解了websocket, HTTP, HTTPS以及openssl的基本知識,便開始了初步的探索,廢話不多說下面就從一個小白的角度來總結一下整個學習的過程,更多的還是以我曾經看過的部落格說起。
一.Socket的再次認識
首先,我們專案的本身是基於websocket的windows自帶的IOCP的方式實施的,為了實施HTTPS的升級,首先要了解什麼是websocket,什麼是HTTP, 以及它們和socket本身的區別:
http://blog.zengrong.net/post/2199.html
這篇部落格講述了上面的問題,我們知道socket是TCP/UDP協議的抽象,簡化了我們對OSI模型實施的難度,它相當於一個API從而使網路以及串列埠通訊都變得極為簡單,可以說如果你想從事串列埠通訊或者網路通訊底層的通訊技術,那麼socket是你必須要掌握的一個重要的知識點;然而據我瞭解在windows系統下socket的本身是有兩套體系(Linux只有一種即同步的方式),一種是同步方式,另一種是非同步方式,所謂同步和非同步,就是是否會發生IO阻塞,同步即是阻塞非同步即是非阻塞,也就是當建立連線以及接收資料的時候是否需要等待;舉個例子來說明第一種同步的傳送資料方式:send(socket, oBuffer.GetBuffer(), dwToPick, 0); 而第二種非同步傳送的方式:WSASend(socket, &m_wsaOutBuffer, 1, &dwSent, ulFlags, &pWriteOverlap->m_ol, NULL);有一點要特別注意的是,如果你想讓WSASend()函式採用非同步方式,當你在建立socket套接字的時候必須要加上WSA_FLAG_OVERLAPPED,否則它就和send()函式沒區別了,都是同步的方式,即 要寫成hSocket = WSASocket(AF_INET, SOCK_STREAM, 0, NULL, 0, WSA_FLAG_OVERLAPPED); WSASend()函式中pWriteOverlap->m_ol引數被稱為是重疊IO和資料報訊息,這個重要的引數將決定了非同步通訊時訊息佇列中訊息的狀態,然而不幸地是這個引數是由作業系統來改變,只有當資料傳送完畢系統才會向訊息佇列傳送完畢通知,這個訊息程式設計師是沒辦法直接改變的,因此導致了我在給HTTP加openssl進行HTTPS升級時不得不徹底推翻整個系統,從新採用Boost.asio庫來實施,當然如果你想挑戰自己,我有一個很好的連結可能會幫助到你,這裡提供瞭如何在windows系統中IOCP模式的socket下進行openssl的實施,並且裡面附帶了原始碼,
http://www.serverframework.com/asynchronousevents/2010/10/using-openssl-with-asynchronous-sockets.html
只可惜筆者不才未能滲透其中的奧祕,而且由於以前系統基於IOCP模式十分多包括整個訊息收發的機制都是與socket本身息息相關的,所以一番糾結過後還是晗著淚放棄了這個方法。
二.Websocket和HTTPS的初探
網上搜索了很多socket和websocket的區別,好多人都說它們倆毛關係沒有,然而本人卻並不這麼認為,我喜歡按照自己的方式去理解,可能有誤但很有效,對此引起對讀者的誤導在此宣告概不負責!我的理解其實socket和websocket的區別不大,只不過前者是TCP的抽象更接近於底層會話層,而websocket更像是為Web端量身定製的一個更接近於應用層的協議,當然websocket的強大之處在於雖然它是HTML5的主要技術,然而它不僅僅只能應用Web還有很多方面;websocket將socket和Http協議的很好的整合了起來,從而它突破了html本身的弊端,即只能由客戶端發起post,服務端響應的方式,websocket則是以全雙工的方式通訊,即連線建立後,客戶端和服務端都可以主動發訊息,並且它的另一大優點是很多瀏覽器都是支援的,可移植性更好資料互動流量會更少的特點,所以建議在網路通訊時使用websockt協議。而HTTPS和HTTP的區別在於,HTTPS實際上是在HTTP協議上加了一個SSL層,從而保證了資料傳輸的安全,具體細節網上一大堆可以很容易的搜到,它最大的優勢就是保障了資料傳輸的安全,畢竟安全第一嘛!然而HTTPS也有自己的弊端它的缺點就是由於需要加密等一系列繁瑣的流程,因而它的傳輸速度比HTTP要慢,具體相差多大讀者可以自己調查,筆者確實不太瞭解,另一個重要的因素,HTTPS需要第三方CA機構的證書認證,這將是一大筆費用,所以在專案中可以按照專案的情況而定。最後分享一個HTTP和HTTPS協議介紹的一個網址,內容可能比較多但很有趣。
http://www.cnblogs.com/zxj015/p/6530766.html
三.Openssl和Boost.asio的認識
由於需要進行HTTPS的升級,openssl便是最佳的實現SSL層的開源庫,openssl是基於socket來實現SSL的,它是附著於socket上,在socket建立連線之後,繫結socket從而建立SSL會話空間,然後用SSL_write()以及SSL_read()來替換掉socket的recv()和send函式的;分享一個openssl簡單實現服務端和客戶端的兩個網址,這裡流程寫的比較詳細,而且有原始碼!
CSDN: http://blog.csdn.net/zqt520/article/details/8791130
部落格園: http://www.cnblogs.com/treecarrybear/p/6219769.html
可惜的是在windows IOCP模式下openssl沒有與之對應的函式,網上有人說可以採用BIO的方式來實施,然而BIO本質上是SSL_xxx()系列函式的一個抽象,從它上面已經看不出socket本身的影子了,所以如果你的專案和我的一樣socket訊息部分應用的很多,那麼恭喜你你沒法使用BIO,如果你非要嘗試,第一節中的那個連結將會對你有很大的幫助,而且stack overflow社群也有一部分這方面的資訊,然而筆者嘗試了很久,最終還是失敗了,如果您在這個升級中成功了的話請務必告訴我,在下將感激不盡。由於上面所說的openssl在我的windows系統IOCP模式下配置失敗,CTO給我的建議是扔掉原來的程式碼,轉到Boost庫上,重新搭建一個全新的HTTPS系統,然而本人對Boost.asio一竅不通,所以從零基礎開始學習,如下是一個很好的Boost.asio學習的網站,與大家分享。
http://blog.csdn.net/zqt520/article/details/8791130
Boost庫的特點是可移植性特別強,無論是windows還是Linux,使用它你可以很容易的實現移植,而且它的功能也十分強大,尤其對於非同步程式設計來說更是不二之選,據說不久的將來它將會加入C++標準庫中,筆者也很期待它的加入,通常非同步程式設計都是基於訊息佇列來傳遞資料收發訊號的,這種訊息佇列的實現起來十分複雜,沒有十幾年的工作經驗很難處理恰當,而Boost庫將這種訊息機制封裝了起來,以一種回撥函式的方式巧妙的實現了訊息的通知,當資料收發完畢後就會觸發回撥函式,從而進行後續處理。如果你採用C++11以及更高的版本,對於簡單的回撥函式,你可以使用lamda表示式來優雅的實現後續處理。Boost庫還有很多其他的優雅而簡潔的功能等著人們去發現。
四.Openssl實現自簽證書
在我的專案中這是一道最大的坎,因為我的系統只是一個windows服務作為服務端,而客戶端是websockt寫的瀏覽器的網頁,並且服務和瀏覽器是在同一臺機器上的;如果你網上找伺服器和證書相關的東西,一大堆的都是Nginx或是Linux伺服器,證書都是Web網站的,必須要有公網IP或是域名,可是我的專案沒有IP和域名啊,我的使用的一定要是本機地址啊,就是127.0.0.1或localhost所以去了好的能提供CA證書的網站諮詢都拒絕提供自簽證書,只能自己生成,所以剛開始生成的證書基本都是由於加密演算法等級太低,被瀏覽器給拒絕了。。。,所以自簽證書的時候,一定要弄明白你的證書的 加密演算法是什麼,還有你的簽名地址一定要寫對,我的專案的地址就是127.0.0.1,兩者缺一都會被瀏覽器給拒絕了,然而你可能並不知道。。。,還有一定要會用openssl的工具進行證書的驗證以及SSL通訊的測試,否則證書這一關將會是你專案中很大的一道阻礙,分享一個比較詳細的自簽證書生成的網址,
http://www.linuxidc.com/Linux/2015-01/112071.htm
這裡有比較詳細的生成過程,當然還有一點要特別注意,要記得修改你的openssl.cnf檔案否則按預設生成的證書,很可能就是因為加密演算法簡單而被瀏覽器拒絕,至於證書如何安裝,你可以參照安裝12306網站的證書同樣的方式即可,還有至今我都沒弄明白橢圓曲線(ECDHE型別的)加密演算法的證書怎麼生成,如何你知道的話,請告訴我一說,對此深表感謝。
五.服務端的配置
對於這一點,本人瞭解甚少,只能分享幾個網址供大家去學習,這些網址都是我花了好久找到的,感覺是最好的,
1.服務配置部落格,這個人的web端的部落格特別棒:
https://imququ.com/post/troubleshooting-https.html
2.SSL測試,以及瀏覽器支援協議查詢的網站,可以讓你很好的瞭解你瀏覽器的屬性:
https://www.ssllabs.com/projects/index.html
3.服務端加密演算法(cipher suite list)以及其他推薦設定的網站:
https://wiki.mozilla.org/Security/Server_Side_TLS#Recommended_configurations
4.github中一個很好的利用boost.asio實現HTTP以及HTTPS的專案:
https://github.com/eidheim/Simple-WebSocket-Server
最後,建議大家專案中最好使用Google而不是百度,雖然我也是支援國產但是說句實話百度的搜尋結果真心不如Google,如果你上不了Google那就偷偷的下一個翻牆軟體吧;只有你想不到的沒有你搜不到的。