朱曄的互聯網架構實踐心得S1E6:給飛機換引擎和安全意識十原則php
【下載本文PDF進行閱讀】前端
本文有兩個部分,先介紹一下給飛機換引擎這個事情個人一些經驗,由於篇幅較短而後介紹一下安全意識方面的一些心得。程序員
所謂給飛行中的飛機(或飛馳的汽車)換引擎說的是咱們須要對一個正在飛速發展的系統進行大幅度的架構改造,好比把All-in-one的架構改形成微服務架構,儘量減小或消除停服的時間。通常而言,咱們能夠這麼來考慮方案,從重構的完全性來講,分爲這麼幾種:數據庫
在作換引擎方案選擇和設計的時候須要考慮到這麼幾個現實的狀況:後端
這種方式的遷移是須要有短暫的停機的,兩個腳本的執行和驗證須要一段時間(數據量大的話導數據費時)。若是但願儘量減小停機時間的話能夠採用兩段走的方式,先同步今天前的99.9%的數據到新數據庫,在停機後再同步今天發生的那0.1%的數據。極端點但願完全不停機的話,須要讓業務同時走兩套系統進行雙寫,這種方案大大增長複雜度,可是能夠換來幾乎0停機的時間,除非是須要24小時在線的金融系統,通常不會考慮新老系統雙活的方案。瀏覽器
你可能會以爲對於重構,咱們應該考慮不要改底層數據庫,這會大大增長複雜性。這仍是取決於咱們但願多完全進行重構,不少時候底層的數據庫設計不夠靈活這是最致命的,若是不切換到新的數據庫,即便搞成了微服務架構數據仍是揉在一塊兒,只是形態上是微服務,底層仍是亂七八糟,這堆業務代碼最終仍是要進行一次重構。緩存
仍是要具體的事情具體來分析,要給飛行中的飛機換引擎,最重要的就是:一、獲得產品方面的配合對需求作好鎖定;二、在開發過程當中對新系統作好充分測試減小上線後修Bug的工做量;三、對遷移方案以及回滾方案作好自動化的腳本以及充分的驗證。安全
對於安全我不是專家,可是我發現有這麼一個問題,那就是作業務開發的同窗每每一點安全意識都沒有,若是有的公司沒有安全方面的部門或專家的話,那麼安全問題真的會很嚴重,外面所謂的一些安全公司的外包滲透服務每每是淺層次的機器作一下掃描和滲透,不多在代碼和邏輯層面作深刻的分析,安全要作好仍是要靠一線程序員和產品經理的點點滴滴的意識。網絡
在這裏,我介紹一下我總結出來的偏產品技術(網絡層面還有不少工做須要作,這裏沒有涉及)方面的安全意識十原則(黑客白帽子確定會有本身的一些成體系的方法論,我這裏更多的是根據以前踩過的坑本身總結的一些經驗):數據結構
一、安全問題是木桶效應。整個系統的安全程度取決於木桶最短的那塊板。不少時候咱們會召集安全專家和架構師和主站主流程主域名的系統進行安全分析和滲透測試,而黑客知道這點也每每喜歡找邊緣化的子站點或非核心邏輯進行攻破,這些模塊或站點每每是由初級程序員打造,有的甚至還不是主站統一的技術架構,整體上會防備薄弱。黑客可以攻破任意站點進去到內網,就有種種可能。針對這點,咱們須要作的是對於安全的排查,須要全面覆蓋,除非子站在部署上用戶體系上完全隔離。
二、開發層面:不要信任客戶端的任何東西。對於HTTP協議,無論是頭裏面的東西(來源、客戶端類型、Cookie)仍是正文裏面的東西,任何數據都是能夠僞造的。咱們每每會以爲Get的東西暴露在瀏覽器地址上,裏面的參數不安全,Post過來的數據由於不暴露就安全,而後會信任Cookie中的數據作一些權限控制,會用頭裏面的一些數據作一些安全性控制。這些不是說不能作,而是要從根子裏面有這個意識全部客戶端的東西能夠用但不能不通過判斷直接相信。有一個容易犯的錯誤是,在設計Controller的時候咱們可能會在參數裏讓客戶端傳過來UserID、Price等信息。這裏的問題在於,登陸後的UserID應該是保存在服務端的,客戶是誰不是客戶本身說了算的,應該是咱們根據SessionID在服務端得到的,咱們須要全面排查代碼,不容許在Controller的方法裏存在相似於用戶ID這樣的字段。對於Price也是同樣的道理,若是這是一個購物的過程,那麼訂單的價格必定是在服務端計算的,咱們只能依靠客戶端傳過來的ItemID來計算價格,不能相信和直接使用客戶端傳過來的價格入庫(僅僅做爲呈現是能夠的,客戶端來的仍是呈如今客戶端,可是不能用於計算)。其實更麻煩的是,不少時候咱們會用框架生成的Controller的CRUD接口的代碼,框架會在參數內直接放上完整的Entity,而後代碼裏會使用這個Entity直接對接數據訪問層入庫,由於客戶端和服務端用JSON在通信,雖然咱們看到客戶端傳給服務端的只是ItemID,可是你再傳一個Price確實也是能夠生效進入Update語句入庫的(Entity某些字段爲空那麼就不會進入Update語句,不爲空就會更新)。下面會再提到這個問題,不少時候用戶看不到的不等於程序邏輯上不可行,服務端的接口層面每每會有比看到的更多的權限(甚至能夠由貫穿數據庫的完整CRUD Restful API)。
三、開發層面:數據就是數據代碼就是代碼。無論是SQL注入也好XSS也好都是這個問題,把數據和代碼混在了一塊兒。對於客戶端過來的任何信息應該都只是數據,應該不多會讓客戶端來告訴服務端執行的代碼。因此這個事情咱們要從兩方面來防範,第一客戶端過來的數據須要讓它當成數據來處理,無論是Encoding一下也好,SQL參數化(Mybatis的$和#問題)也好都是這個方面的措施(從前到後一路數據都以數據的身份在程序中流轉),第二從數據庫裏出來的東西也只能是數據不能讓它變爲HTML或JS代碼,也須要Encoding一次再在客戶端上呈現。SQL注入的防範不少人喜歡用敏感字符替換的方式來作,這種作法實際上是會有遺留的,咱們不該該去考慮排除數據中有代碼的可能性,而是應該從根源上去讓數據只可能成爲數據。
四、開發層面:用戶看不到不等於黑客看不到。第一個方面想說的是,隨着先後端的分離,如今不少請求都是AJAX請求,AJAX請求會有幾方面的安全疏漏:
第二方面說的是,後端每每會返回更多的數據給前端,前端選擇須要的數據進行呈現,有的時候甚至直接返回的是代碼生成器生成的DbEntity(在三層架構中,DbEntity對應表結構,ServiceEntity是充血的領域實體,ResponseEntity是面向呈現的實體,三者不該該是一套)。這裏的問題在於:
這就要求咱們在作設計的時候儘量仔細審視AJAX的接口的權限、數據開放性和脫敏等問題。一些框架提供的腳手架生成工具以及Restful API自動生成工具,即便要用也要作好權限設置。
五、開發層面:最小化接口權限設計複用性矛盾。在作設計的時候咱們會考慮到複用性的問題讓方法儘量通用,可是對於對外的接口咱們要儘可能收縮功能。舉一個以前看到的例子,咱們須要驗證遊戲的密保卡,須要用戶告知三個座標的密保數字,好比A1B2C3三個座標,每個數字是0到99,三個數字同時猜對的可能性是百萬分之一,可是接口的設計竟然是直接讓用戶傳三個座標,這裏有兩個嚴重的設計錯誤:
在設計服務端接口的時候,咱們最好針對某個功能設計最小的接口,而不是開放的通用的接口,對外的接口設計安全性須要大於重用性。
六、開發層面:一開始就要考慮安全,放出去了就沒後悔藥。比較無奈的是,不少項目咱們處於趕進度,一開始初版的時候並無對接口作加密和簽名驗證。若是作的是一個APP,那麼咱們要考慮到APP用戶不升級的狀況,即便v2的版本的數據都是加密的,參數都是驗籤的,可是咱們還不能下架v1版本(強更會損失多少用戶難以估計)。這個時候就比較無奈了,明知道v1版本的安全性有着很大的風險卻不能升級。不只僅是接口的安全性,安卓客戶端的代碼也要考慮到反編譯的可能性須要混淆。以前遇到過有一個App客戶端裏網絡層直接使用了服務端的接口定義,致使客戶端代碼裏能夠對服務端全部接口一清二楚,還不乏一些不能對外使用的內部接口以及已經淘汰的老接口,加上接口的調用又沒有簽名數據傳輸又不加密,拿着這份網絡協議什麼均可以幹。
七、產品層面:作好防刷和暴力破解控制。顯性的功能當然重要,可是產品經理也須要在隱性功能和風控策略上下一些功夫,產品經理沒有這方面意識的話開發每每更不太會作深刻考慮。包括:
重要的業務須要有風控方面的產品經理和業務產品經理一塊兒來參與,共同討論流程,防羊毛,防黑客, 防刷子。
八、產品層面:注意產品邏輯一體性。不少業務流程是受權-執行這樣的兩步,但有些時候這兩步在產品設計的時候並不必定是同一個產品經理在設計,會出現受權和執行不一致的狀況。見過一個修改綁定郵箱的產品邏輯,用戶在頁面X先進行短信驗證碼驗證,而後就能夠跳轉到Y頁面進行修改綁定郵箱,X頁面是通用的短信驗證頁面,Y是新的修改綁定郵箱的需求,這裏出現一個邏輯漏洞,就是在X頁面驗證完成後進入Y頁面,若是這個時候利用另一個TAB退登登陸切換用戶後,在Y頁面仍是能夠修改綁定郵箱的,這個時候程序從Session中讀取的到用戶並非以前那個經過短信驗證的用戶,而是後面登陸的新用戶,至關於咱們就能夠爲任意用戶修改綁定郵箱了。對於多步走的邏輯,咱們必定要做爲一個總體來思考。黑客在尋找突破的時候特別喜歡尋找ABC幾步走的邏輯,而後嘗試最後一步C是否能夠單獨來作尋找邏輯方面的漏洞。
九、運維層面:作好異常數據監控報警。在運營層面,咱們須要對方方面面的數據有報表或監控,對於異常的數據徒增及時進行調查,業務量的增長若是不伴隨活動或推廣的話不必定是好事情。在運維層面,咱們一樣也須要對網絡磁盤的使用徒增以及服務的調用量上升查明緣由,看看這是業務致使的仍是多是安全性問題。對於各類三方服務(好比短信通道、CDN、文件存儲等)的使用,最好也有日報級別的監控,以避免看到月度的帳單後再發現被刷的問題哭都來不及。
十、運維層面:對內的數據和權限問題。咱們說內部人是最難防的,內部系統繁雜,受權和審計作的可能不那麼完善,內部人員若是有心的話獲取一些數據作一些壞事形成的影響會比較大,咱們須要從幾方面來作一些措施: