閱讀筆記--互聯網架構實踐:給飛機換引擎和安全意識十原則

     在閱讀文章以前,被文章標題所吸引,見過給車換引擎,還從沒見過給飛機換引擎,因此對這篇文章很感興趣,想了解飛機如何更換引擎。本身想象的飛機引擎應該很大很大,得幾個成年人才擡得動,引擎上的器件必定特別堅固而精細,綜合以上所想,給飛機更換引擎是個困難而複雜的工做。php

     經過閱讀這篇文章得知換引擎要考慮不少事情:前端

所謂給飛行中的飛機(或飛馳的汽車)換引擎說的是咱們須要對一個正在飛速發展的系統進行大幅度的架構改造,好比把All-in-one的架構改形成微服務架構,儘量減小或消除停服的時間。通常而言,咱們能夠這麼來考慮方案,從重構的完全性來講,分爲這麼幾種:程序員

  • 完全從新作,直接從前到後拋棄老系統數據庫

  • 大規模重構,保留對用戶的這層皮,後面從服務到數據所有替換後端

  • 小規模重構,保留對用戶的這層皮以及數據結構,逐一替換核心邏輯到微服務瀏覽器

在作換引擎方案選擇和設計的時候須要考慮到這麼幾個現實的狀況:緩存

  • 業務須要發展。意味着會不斷有新需求須要開發,若是重構的時間拖的很長的話,咱們須要在這段很長的時間內爲兩套系統同時作新需求,新的系統還要不斷開發新需求,會增長更多的時間,若是新系統的開發不夠快的話,甚至一直上不了線。咱們最好在重構以前對新增業務有一條界限,新系統只是覆蓋到這個版本作需求封板,而後和產品商量出一個妥協是否對於以後咱們留1周做爲系統切換期,這段時間不上線新需求。這1周分紅幾個環節,須要2天的時間來作系統切換,而後須要5天的時間來觀察新系統的穩定性,修復新系統的Bug,隨後咱們才能認爲系統正式切換成功,把時間精力放到新業務的開發上。安全

  • 數據須要遷移。咱們是爲一箇舊飛機在換引擎,沒法拋棄飛機上的乘客。若是咱們更改數據結構的話,須要對數據進行遷移。咱們須要作下面的工做:網絡

    • 準備遷移腳本數據結構

    • 準備緩存預熱腳本

    • 使用既有的數據來測試這2個腳本,而後觀察新系統的運行狀況

    • 作反向數據遷移的腳本,咱們要考慮到切換到新系統後運行不流暢須要總體回滾的狀況,這個時候咱們須要把數據重新的數據庫遷移回老的數據庫

這種方式的遷移是須要有短暫的停機的,兩個腳本的執行和驗證須要一段時間(數據量大的話導數據費時)。若是但願儘量減小停機時間的話能夠採用兩段走的方式,先同步今天前的99.9%的數據到新數據庫,在停機後再同步今天發生的那0.1%的數據。極端點但願完全不停機的話,須要讓業務同時走兩套系統進行雙寫,這種方案大大增長複雜度,可是能夠換來幾乎0停機的時間,除非是須要24小時在線的金融系統,通常不會考慮新老系統雙活的方案。

你可能會以爲對於重構,咱們應該考慮不要改底層數據庫,這會大大增長複雜性。這仍是取決於咱們但願多完全進行重構,不少時候底層的數據庫設計不夠靈活這是最致命的,若是不切換到新的數據庫,即便搞成了微服務架構數據仍是揉在一塊兒,只是形態上是微服務,底層仍是亂七八糟,這堆業務代碼最終仍是要進行一次重構。

  • 最好沒有停機讓用戶沒有感知。沒有停機意味着老的系統一直在線上穩定運行,新的系統能夠以獨立的形態從新部署一套,用戶對咱們新系統的開發沒有感知。新老系統的面子能夠長得如出一轍,可是底層的調用面目全非。因爲兩套系統都在線上運行,咱們能夠在內部對新系統進行充分測試,還能夠比較一樣的業務流程在數據呈現上是否有差別。惋惜現實每每沒有想象的這麼簡單,不少時候咱們會依賴各類三方數據,對於金融系統來講每每對接了銀行的系統,這不是依賴這麼簡單了,而是完徹底全的依賴。若是咱們依賴的第三方會受到咱們重構的影響,或是咱們就是在切換依賴方的話,是否停機就不是本身能夠掌控的了,第三方須要有停機咱們就只能停機。這個時候咱們能作的是,讓網站進行部分功能的停機而不是總體停機,用戶能夠以只讀形式使用網站的全部功能,可是不能作寫入操做,待三方系統切換完成後切換到新系統了才能使用全部功能,這樣用戶也會有安全感。

  • 萬一遷移失敗怎麼辦。以前說了咱們遷移數據須要考慮回滾方案,這裏還會有一些比較噁心的點是若是新老系統有一些內部外部依賴是公用的話,儘可能要隔離清楚,讓新老系統完全獨立,這樣纔好回滾,若是遷移後新系統在跑了污染了老系統的數據,這個時候再要回滾會出現回不去的狀況,由於老系統沒法適應新的數據。內部要進行完全的隔離是比較簡單,對於三方的數據(好比CDN)咱們也要考慮到數據在邊緣節點和用戶端緩存的狀況,在設計方案的時候就要考慮到切換後回退的可能性,儘量讓兩套系統使用獨立的數據不要產生數據覆蓋的狀況形成污染。

仍是要具體的事情具體來分析,要給飛行中的飛機換引擎,最重要的就是:

  • 獲得產品方面的配合對需求作好鎖定;

  • 在開發過程當中對新系統作好充分測試減小上線後修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語句,不爲空就會更新)。

三、開發層面:數據就是數據代碼就是代碼。無論是SQL注入也好XSS也好都是這個問題,把數據和代碼混在了一塊兒。對於客戶端過來的任何信息應該都只是數據,應該不多會讓客戶端來告訴服務端執行的代碼。因此這個事情咱們要從兩方面來防範,第一客戶端過來的數據須要讓它當成數據來處理,無論是Encoding一下也好,SQL參數化(Mybatis的$和#問題)也好都是這個方面的措施(從前到後一路數據都以數據的身份在程序中流轉),第二從數據庫裏出來的東西也只能是數據不能讓它變爲HTML或JS代碼,也須要Encoding一次再在客戶端上呈現。SQL注入的防範不少人喜歡用敏感字符替換的方式來作,這種作法實際上是會有遺留的,咱們不該該去考慮排除數據中有代碼的可能性,而是應該從根源上去讓數據只可能成爲數據。

四、開發層面:用戶看不到不等於黑客看不到。第一個方面想說的是,隨着先後端的分離,如今不少請求都是AJAX請求,AJAX請求會有幾方面的安全疏漏:

  • 邏輯分散而明確。對於服務端渲染,咱們會把各類邏輯整合在一塊兒,用戶看到的是一個完整的渲染後的頁面不清楚裏面有多少邏輯,對於AJAX請求,咱們會以良好的方法命名來命名各類API。這個時候會給黑客可乘之機,會更容易分析理解程序運行的流程,畢竟在尋找突破以前須要先理解程序的流程。

  • 容易以爲AJAX請求是前端程序發起的而忽略權限問題。沒錯,AJAX的發起人也是咱們的代碼,可是AJAX請求也是HTTP請求誰均可以發起。若是咱們對AJAX請求的參數設計有所鬆懈,犯了以前說的兩個錯的話那就很危險了。特別是先後端都是一我的來寫的話,程序員在實現代碼邏輯的時候每每只會考慮數據的傳輸簡單通暢,後端給前端,前端再給後端放鬆安全意識。

五、開發層面:最小化接口權限設計複用性矛盾。在作設計的時候咱們會考慮到複用性的問題讓方法儘量通用,可是對於對外的接口咱們要儘可能收縮功能。舉一個以前看到的例子,咱們須要驗證遊戲的密保卡,須要用戶告知三個座標的密保數字,好比A1B2C3三個座標,每個數字是0到99,三個數字同時猜對的可能性是百萬分之一,可是接口的設計竟然是直接讓用戶傳三個座標,這裏有兩個嚴重的設計錯誤:

  • 第一,爲何是容許客戶端傳過來三個密保的位置,合理的作法是服務端告知客戶端這次校驗的ID,而後客戶端傳過來ID,服務端在Session或緩存中去獲取座標位置。

  • 第二,接口容許傳三個座標也算了,還容許是相同的座標,咱們徹底能夠改造接口傳A1A1A1而後依次暴力破解0到99,立刻就能夠得出A1座標的值,幾秒的時間就能夠把整個密保卡徹底暴破出來。

在設計服務端接口的時候,咱們最好針對某個功能設計最小的接口,而不是開放的通用的接口,對外的接口設計安全性須要大於重用性。

六、開發層面:一開始就要考慮安全,放出去了就沒後悔藥。比較無奈的是,不少項目咱們處於趕進度,一開始初版的時候並無對接口作加密和簽名驗證。若是作的是一個APP,那麼咱們要考慮到APP用戶不升級的狀況,即便v2的版本的數據都是加密的,參數都是驗籤的,可是咱們還不能下架v1版本(強更會損失多少用戶難以估計)。這個時候就比較無奈了,明知道v1版本的安全性有着很大的風險卻不能升級。不只僅是接口的安全性,安卓客戶端的代碼也要考慮到反編譯的可能性須要混淆。以前遇到過有一個App客戶端裏網絡層直接使用了服務端的接口定義,致使客戶端代碼裏能夠對服務端全部接口一清二楚,還不乏一些不能對外使用的內部接口以及已經淘汰的老接口,加上接口的調用又沒有簽名數據傳輸又不加密,拿着這份網絡協議什麼均可以幹。

七、產品層面:作好防刷和暴力破解控制。顯性的功能當然重要,可是產品經理也須要在隱性功能和風控策略上下一些功夫,產品經理沒有這方面意識的話開發每每更不太會作深刻考慮。包括:

  • 公開出去的短信驗證碼服務防刷控制(防止被刷子利用作短信轟炸),在用戶體驗和防刷上作平衡,好比到達必定的頻次後出驗證碼,服務端對客戶端的一些頭作校驗(刷子通常不知道這樣的邏輯)等等。不只僅是短信驗證碼,公開出去的不須要受權就能夠用的服務都須要防刷。

  • 登陸是用戶從匿名進入受權的重要環節,對這一環節作一些策略。好比異地登陸提醒、錯誤登陸後出驗證碼、太屢次錯誤後禁用等等。

  • 涉及到積分、兌換、返現、抽獎這種和錢打交道的業務,要多考慮是否會有刷的可能,不只僅是程序邏輯方面的漏洞,惟一性的判斷,還要考慮積分流通起來後是否會有擼羊毛小換大的可能。有利益的地方就有羊毛,若是一個業務都是羊毛在參與的話那麼帳面數據可能挺好看,但實際上幾乎帶來不了忠實的有留存的用戶。

重要的業務須要有風控方面的產品經理和業務產品經理一塊兒來參與,共同討論流程,防羊毛,防黑客, 防刷子。

八、產品層面:注意產品邏輯一體性。不少業務流程是受權-執行這樣的兩步,但有些時候這兩步在產品設計的時候並不必定是同一個產品經理在設計,會出現受權和執行不一致的狀況。見過一個修改綁定郵箱的產品邏輯,用戶在頁面X先進行短信驗證碼驗證,而後就能夠跳轉到Y頁面進行修改綁定郵箱,X頁面是通用的短信驗證頁面,Y是新的修改綁定郵箱的需求,這裏出現一個邏輯漏洞,就是在X頁面驗證完成後進入Y頁面,若是這個時候利用另一個TAB退登登陸切換用戶後,在Y頁面仍是能夠修改綁定郵箱的,這個時候程序從Session中讀取的到用戶並非以前那個經過短信驗證的用戶,而是後面登陸的新用戶,至關於咱們就能夠爲任意用戶修改綁定郵箱了。對於多步走的邏輯,咱們必定要做爲一個總體來思考。黑客在尋找突破的時候特別喜歡尋找ABC幾步走的邏輯,而後嘗試最後一步C是否能夠單獨來作尋找邏輯方面的漏洞。

九、運維層面:作好異常數據監控報警。在運營層面,咱們須要對方方面面的數據有報表或監控,對於異常的數據徒增及時進行調查,業務量的增長若是不伴隨活動或推廣的話不必定是好事情。在運維層面,咱們一樣也須要對網絡磁盤的使用徒增以及服務的調用量上升查明緣由,看看這是業務致使的仍是多是安全性問題。對於各類三方服務(好比短信通道、CDN、文件存儲等)的使用,最好也有日報級別的監控,以避免看到月度的帳單後再發現被刷的問題哭都來不及。

十、運維層面:對內的數據和權限問題。咱們說內部人是最難防的,內部系統繁雜,受權和審計作的可能不那麼完善,內部人員若是有心的話獲取一些數據作一些壞事形成的影響會比較大,咱們須要從幾方面來作一些措施:

  • 線上的配置儘可能加密,配置信息和代碼分離

  • 敏感數據(用戶信息)在數據庫中加密保存

  • 線上數據訪問須要使用相似於phpmyadmin的Web網站,不容許使用客戶端工具,這樣能夠作比較健全的受權,防止數據導出

  • 內部系統涉及到用戶信息部分脫敏顯示,顯示完整的數據須要上級受權

  • 全部內部系統的登陸和使用須要有完整的日誌,對日誌進行分析和按期的審計

 總結:經過閱讀這篇文章,我瞭解到安全性的重要性涉及到開發層面,產品層面,運維層面以及應對這些安全性問題得解決辦法。讓我在之後的產品開發過程當中更加的有經驗,少範錯誤。

相關文章
相關標籤/搜索