互聯網中TCP Socket伺服器的實現過程需要考慮哪些安全問題?
問題來源於,陳碩老師介紹muduo庫的一個視頻。
其中提到muduo的設計目標是主要用於內網服務,沒有針對處理公網服務中五花八門的網路攻擊
作為一般的應用層程序員,比如說實現一個私有協議的遊戲伺服器,在編碼過程中,需要考慮的網路攻擊或者安全防禦的點,一般都有哪些呢?
首先,這是個很大的命題,之前在360負責過幾個對外的服務的研發,也算是有點小經驗,我試著答一下:
在Internet環境下,安全問題我主要分為如下幾類:
- 信息傳輸過程中被黑客竊取
- 伺服器自身的安全
- 服務端數據的安全
首先,如果能用https,就盡量用https,能用nginx等常見伺服器,就用常見伺服器,主要能避免以下問題:
- 自己實現的協議Server端可能會有各種Bug,被緩衝區溢出攻擊等
- SSL加密體系在防監聽方面已經足夠成熟,值得信賴
所幸,私有協議服務的攻擊需要黑客分析協議,這就給一般的小服務增加了一層保護。但如果是在大公司做事,樹大招風,就必須至少做到理論上沒有安全漏洞。神馬,xor混淆一下,C/S端寫死一個對稱密鑰這種掩耳盜鈴的事情就不要做了,不然會死的很難看。
如果需要自己實現Server端,實現一套合格的SSL還是很考驗功底的:
- 首先要弄明白SSL加密體系密鑰交換的原理
- 對各種對稱、非對稱加密演算法要有深刻的理解
- 用非對稱加密演算法怎麼實現一套密鑰交換體系
- 如何處理ca證書,在自簽名情況下怎麼避免中間人攻擊
工程實現過程中,要考慮:
- 各種可能的緩衝區溢出攻擊
- SYN flood攻擊,慢連接攻擊
- DDoS防起來有難度,但至少能防禦DoS攻擊
業務邏輯層面,要考慮:
- 每個介面都要做好用戶許可權驗證
- 介面會不會被人亂用,重放攻擊
- 攻擊方會不會找到一個比較消耗服務端資源的介面,用很小的代價耗盡服務端資源
- 用戶的用戶名密碼會不會被通過介面破解,參見:2014 celebrity photo hack
- 你的服務會不會被黑客利用去攻擊別的服務,特別是會根據用戶輸入抓取什麼資源的服務
- 古老的SQL注入
- 無恥的仿冒服務,DNS欺詐
- 涉及HTML的,還要考慮跨站……
即使你做到了天衣無縫,還要考慮隊友有時會掉鏈子:
- glibc、openssl這些基礎的庫也會爆出漏洞,參見:Heartbleed
- 同一台主機上的其它服務被攻陷
沒有踩過很多坑,哪裡知道很多事。寫完之後整個人都不好了
內容安全考慮,非對稱加密交換密鑰(RSA/DH),然後對稱加密(RC4/RC5)進行通信。即使盤路監聽了,也無法獲取你的通信內容。如果嫌棄 RSA太龐大,不想上 openssl/polarssl的話,可以用 DH演算法,上64位整數,實現一個64位整數的快速 PowMod,參考 Russian Peasant multiplication 和 Right-to-left binary method 來實現快速運算,大質數事先固定(免去沉重的質數生成計算),每秒鐘計算上幾十萬次密鑰交換應該不是大問題。
內網篇
如果只是在內網,別用那些獨立作者開發的亂七八糟的東西。
VC、C#這些語言可以用WCF,最智能最方便的通信組件,不需要寫業務無關的通信代碼,全部點滑鼠完成。
Java、PHP、Python等其他語言可以用Thrift,雖然沒WCF方便,但在定義了通信數據結構與方法文件後,也能自動生成各種語言的通信代碼。
說到這裡,會有很多人會不服:
1.Q:為何不用pb(protocol buffer)?
A:因為pb支持的語言沒有Thrift廣泛全面;而且pb只是一套協議,沒有官方實現的通信承載程序。非官方的其他語言支持與通信承載程序,你敢在生成機器上用?我保證老闆不會打死你。
2.Q:我是XXX通信框架的獨立開發者,我寫的XX框架比Thrift性能高N倍,比Thrift方便M倍。為何不用我寫的框架?
A:為什麼用框架?那是為了追求開發的方便,追求開發的高效率。如果只為高性能,我為何不根據業務直接寫高度優化的硬編碼的協議?這樣無論什麼通用框架,只要它是通用的,肯定沒根據業務優化的專用框架性能高。
而且,真的比Thrift方便?我是見過不少作者號稱比Thrift方便,但也只是號稱而已,實際上他們會故意忽略很多細節。真正去花時間做一次對比測試,會發現並不比Thrift方便。
而且,更麻煩的是,如果作者停止更新,或者沒時間修復Bug呢?
--------------------
外網篇
在外網,其實直接用成熟的http server就好了,比如Apache、IIS、Nginx什麼的,因為走這些方案,你遇到的幾乎任何問題,都有現成的解決方案。
比如:要安全,有https;要防黑,有身份驗證、注入檢測過濾;要防攻擊,有硬體防火牆,等等。
至於要用什麼協議,可以走成熟的WebService啊。現在幾乎所有能做服務端開發的語言,都有成熟、方便的WebService開發方案。不過我還是推薦C#的WebService,太方便了。至於跨域問題么?用Apache,花幾分鐘做一個逆向代理就行了。
.我說幾個比較常見的。
1.三次握手,到底完成了么?常見的攻擊就是不完成3次握手,導致你的backlog隊列塞滿,而沒有任何accept發生,這會導致後續的連接被拒絕。因此第一步就是要幹掉沒有在規定時間內完成3次握手的連接,並且最好將該ip短時間內拉入黑名單(20秒,1分鐘之類)。
2.異常數據,異常的數據會導致邏輯不嚴謹的代碼觸發一些不確定的行為。因此在協議設計的時候,要為不符合預期的數據做好準備。常見的比如 數據包的包長度必須限制在一個規定的範圍內,而不是shrot 或者 int 的長度。對於在此之上的文件傳輸,最好另開結點或者為此定製一個文件傳輸協議(即分割文件)。
3.長期空閑,定時檢查超時連接是避免不了的,除非存在掛機的現象(網遊),否則對於不活躍的連接應當直接清除。
4.數據的加密和解密,這個老生常談了,照著方法就好。
5.socket不正常關閉的情況,socket連接的關閉需要4次握手,但通常很難確保該握手會完成,因此應當強制清理需要關閉的socket。
6.第三方客戶端,任何未授權的應用都不能調用目標伺服器上的數據,協議設計時應當考慮鑒權和確保非第三方客戶端的機制。
7.邏輯和數據伺服器,絕對不應該放在整個網路的前面(即客戶直連的地方),不管你是自定義協議or常用協議,用戶連接到的伺服器應該是你們的網關伺服器,再由網關伺服器轉發(可以變換協議)到內部伺服器上。隨便說說,不是很嚴謹
從常見的威脅看
1:ddos攻擊 你是不是土豪,土豪就上硬體防火牆 .如果不是代碼上支持這幾個邏輯 a非法協議過濾 b 已經經過安全檢驗的業務和驗證業務在線程或進程上分開 c支持動態的更換業務介面IP 快速切換業務
2:針對業務邏輯的 a 協議最好加密 b 邏輯內容上對每個用戶的輸入進行檢查,能不用用戶數據的地方就不用
防止ddos攻擊,最常見的ddos攻擊就是通過tcp實現的
推薦閱讀: