誰家的加密金鑰,寫死在代碼里?
誰家的加密金鑰,寫死在代碼里?
系統設計,協定先行。
大部分人不瞭解協議的設計細節,更多使用已有協議進行應用層設計,例如:
- 使用HTTP,設計 get/post/cookie 參數,以及json包格式;
- 使用dubbo,而不用去深究內部的二進位包頭包體細節;
無論如何,瞭解協議設計的原則,對深入理解系統通信非常有説明。
一、協定的分層設計
所謂「協定」,是雙方共同遵守的規則,例如:離婚協定,停戰協定。 協議有語法、語義、時序三要素:
- 語法,即數據與控制信息的結構或格式;
- 語義,即需要發出何種控制資訊,完成何種動作以及做出何種回應;
- 時序,即事件實現順序的詳細說明;
畫外音:後文主要講語法設計。
協議設計通常分為三層:應用層協定、安全層協定、傳輸層協定。
下面分別看下這三層的協議應該如何選型。
二、應用層協議設計
應用層協議選型,常見的有三種:文本協定、二進制協定、流式XML協定。
(1) 文字協定
文本協定是指「貼近人類書面語言表達」的通訊傳輸協定,典型的協定是HTTP協定,一個HTTP協定的請求報文樣例如下:
GET / HTTP/1.1
User-Agent: curl
Host: musicml.net
Accept: */*
- 1.
- 2.
- 3.
- 4.
文字協議的特點是:
- 可讀性好,便於調試;
- 擴展性較好,能通過key:value擴展;
- 解析效率不高,一行一行讀入,按照冒號分割,解析key和value;
- 對二進位不友好 ,比如語音/視頻等;
(2) 二進位協定
二進位協定即binary協定,典型是IP協定,以下是IP協定的一個圖示:
二進位協定一般包含:一般包含:
- 定長包頭;
- 可擴展變長包體;
- 一般每個欄位有固定的含義,以IP協定為例,前4個bit表示協定版本號(Version);
二進位協議的特點是:
- 可讀性差,難於調試; 畫外音:打日誌一般需要一個toString()函數增強可讀性。
- 擴展性不好,如果要擴展欄位,舊版協定就不相容了,所以設計時一般會有一個Version字段;
- 解析效率超高,幾乎沒有解析代價,二進位流的每個字段表示固定含義;
- 天然支援二進位流 ,比如語音/視頻;
這是一個典型的16位元組二進制定長包頭的例子:
//sizeof(cs_header)=16
struct cs_header {
uint32_t version;
uint32_t magic_num;
uint32_t cmd;
uint32_t len;
uint8_t data[];
}__attribute__((packed));
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
其中:
(1)前4個字節表示版本號version;
(2)接下來4個字節表示魔法數位magic_num,用來解決數據錯位或丟包問題;
畫外音:例如,約定好魔法數位是0x01020304,收到的報文,魔法數位匹配,認為是正常報文,否則認為是報文異常,斷開連接。
(3)接下來4個字節表示命令號command,不同的命令號對應不同的變長包體;
(4)最後4個字節表示包體長度length,以確定變長包體有多少位元組;
這是一個實際的二進位變長包體:
message CUserLoginReq {
optional string username = 1;
optional string passwd = 2;
}
message CUserLoginResp {
optional uint64 uid =1;
}
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
它使用的是Google的Protobuf協定,容易看到:
- 請求報文傳入的是使用者名與密碼;
- 回應包返回的是使用者的uid;
PB是很流行的二進位變長包體協定,其優點為:
- 通用,可以生成C++、Java、PHP等多語言代碼;
- 自帶壓縮功能;
- 對二進位友好;
- 在工業界已廣泛應用; 畫外音:Google出品,必屬精品。
流式XML協定流式XML似乎是文本協定的一個特例,亦可以單獨作為一類。 例如:xmpp就是典型的流式XML協定,下面是xmpp協定的一個典型報文:
<message
to=’romeo@example.net’
from=’juliet@example.com’
type=’chat’
xml : lang=’en’>
<body>Wherefore art thou, Romeo?</body>
</message>
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
從xml標籤中大致可以判斷這是一個romeo發給juliet的聊天消息。
XML協定有幾個特點:
- 可讀性好,擴展性好,這是XML的特性;
- 解析代價超高,需要進行dom樹分析;
- 有效數據傳輸率超低,有大量的標籤;
- 對二進位不友好 ,比如語音/視頻等;
三、安全層協議設計
安全層協議設計,除了使用SSL,自行實現的話,常見的又有以下三種方案。
畫外音:SSL秘鑰管理是個問題。
(1) 固定金鑰
服務端和客戶端約定好一個密鑰,同時約定好一個加密演算法(例如:AES),每次用戶端發送報文前,就用約定好的演算法,以及約定好的密鑰加密再傳輸,服務端收到報文后,用約定好的演算法,約定好的密鑰再解密。
畫外音:安全性低,安全性基於程式師的職業操守。
(2) 一人一密
簡單來說,就是一個人的密鑰是固定的,但是每個人之間又不同。 常見的實現方式是:
- 固定加密演算法;
- 加密秘鑰使用「使用者的某一特殊屬性」,比如使用者uid、手機號、qq號、用戶密碼等;
(3) 一次一密
即動態金鑰,一Session一金鑰的安全性更高,每次會話前協商密鑰。 密鑰協商的過程要經過2次非對稱金鑰的隨機生成,1次對稱加密密鑰的隨機生成,具體詳情這裡不展開。
四、傳輸層協議設計
可選的協定有TCP和UDP,現在基本都是使用TCP,有了epoll等技術后,多連接就不是瓶頸了,單機幾十萬鏈接沒什麼問題。