Java生鮮電商平臺-安全設計與架構

Java生鮮電商平臺-安全設計與架構算法

 

說明:Java開源生鮮電商平臺是一個B2B的生鮮電商平臺,因爲是APP的一種模式,因此安全方面通常會思考如下幾個維度:json

           1.數據安全。api

            2.傳輸安全。數組

App與服務器的通訊接口如何設計得好,須要考慮的地方挺多的,在此根據個人一些經驗作一些總結分享,旨在拋磚引玉。安全

安全機制的設計

如今,大部分App的接口都採用RESTful架構,RESTFul最重要的一個設計原則就是,客戶端與服務器的交互在請求之間是無狀態的,也就是說,當涉及到用戶狀態時,每次請求都要帶上身份驗證信息。實現上,大部分都採用token的認證方式,通常流程是:服務器

  1. 用戶用密碼登陸成功後,服務器返回token給客戶端;
  2. 客戶端將token保存在本地,發起後續的相關請求時,將token發回給服務器;
  3. 服務器檢查token的有效性,有效則返回數據,若無效,分兩種狀況:
    • token錯誤,這時須要用戶從新登陸,獲取正確的token
    • token過時,這時客戶端須要再發起一次認證請求,獲取新的token

然而,此種驗證方式存在一個安全性問題:當登陸接口被劫持時,黑客就獲取到了用戶密碼和token,後續則能夠對該用戶作任何事情了。用戶只有修改密碼才能奪回控制權。微信

如何優化呢?第一種解決方案是採用HTTPS。HTTPS在HTTP的基礎上添加了SSL安全協議,自動對數據進行了壓縮加密,在必定程序能夠防止監聽、防止劫持、防止重發,安全性能夠提升不少。不過,SSL也不是絕對安全的,也存在被劫持的可能。另外,服務器對HTTPS的配置相對有點複雜,還須要到CA申請證書,並且通常仍是收費的。並且,HTTPS效率也比較低。通常,只有安全要求比較高的系統纔會採用HTTPS,好比銀行。而大部分對安全要求沒那麼高的App仍是採用HTTP的方式。數據結構

咱們目前的作法是給每一個接口都添加簽名。給客戶端分配一個密鑰,每次請求接口時,將密鑰和全部參數組合成源串,根據簽名算法生成簽名值,發送請求時將簽名一塊兒發送給服務器驗證。相似的實現可參考OAuth1.0的簽名算法。這樣,黑客不知道密鑰,不知道簽名算法,就算攔截到登陸接口,後續請求也沒法成功操做。不過,由於簽名算法比較麻煩,並且容易出錯,只適合對內的接口。若是大家的接口屬於開放的API,則不太適合這種簽名認證的方式了,建議仍是使用OAuth2.0的認證機制。架構

咱們也給每一個端分配一個appKey,好比Android、iOS、微信三端,每一個端分別分配一個appKey和一個密鑰。沒有傳appKey的請求將報錯,傳錯了appKey的請求也將報錯。這樣,安全性方面又加多了一層防護,同時也方便對不一樣端作一些不一樣的處理策略。app

另外,如今愈來愈多App取消了密碼登陸,而採用手機號+短信驗證碼的登陸方式,我在當前的電商項目中也採用了這種登陸方式。這種登陸方式有幾種好處:

  1. 不須要註冊,不須要修改密碼,也不須要由於忘記密碼而重置密碼的操做了;
  2. 用戶再也不須要記住密碼了,也不怕密碼泄露的問題了;
  3. 相對於密碼登陸其安全性明顯提升了。

接口數據的設計

接口的數據通常都採用JSON格式進行傳輸,不過,須要注意的是,JSON的值只有六種數據類型:

  • Number:整數或浮點數
  • String:字符串
  • Boolean:true 或 false
  • Array:數組包含在方括號[]中
  • Object:對象包含在大括號{}中
  • Null:空類型

因此,傳輸的數據類型不能超過這六種數據類型。之前,咱們曾經試過傳輸Date類型,它會轉爲相似於"2016年1月7日 09時17分42秒 GMT+08:00"這樣的字符串,這在轉換時會產生問題,不一樣的解析庫解析方式可能不一樣,有的可能會轉亂,有的可能直接異常了。要避免出錯,必須作特殊處理,本身手動去作解析。爲了根除這種問題,最好的解決方案是用毫秒數表示日期。

另外,之前的項目中還出現過字符串的"true"和"false",或者字符串的數字,甚至還出現過字符串的"null",致使解析錯誤,尤爲是"null",致使App奔潰,後來查了很久才查出來是該問題致使的。這都是由於服務端對數據沒處理好,致使有些數據轉爲了字符串。因此,在客戶端,也不能徹底信任服務端傳回的數據都是對的,須要對全部異常狀況都作相應處理。

服務器返回的數據結構,通常爲:

{
    "code":"200", "message": "請求成功", "Object": { key1: value1, key2: value2, ... } } 
  • code: 返回碼,200表示成功,非200表示各類不一樣的錯誤
  • message: 描述信息,成功時爲"請求成功 ",錯誤時則是錯誤信息
  • object: 成功時返回的數據,類型爲

不一樣錯誤須要定義不一樣的返回碼,屬於客戶端的錯誤和服務端的錯誤也要區分,好比1XX表示客戶端的錯誤,2XX表示服務端的錯誤。這裏舉幾個例子:

  • 200:成功
  • 201:請求錯誤
  • 202:缺乏appKey
  • 203:缺乏簽名
  • 204:缺乏參數
  • 205:服務器出錯
  • 206:服務不可用
  • 207:服務器正在重啓

錯誤信息通常有兩種用途:一是客戶端開發人員調試時看具體是什麼錯誤;二是做爲App錯誤提示直接展現給用戶看。主要仍是做爲App錯誤提示,直接展現給用戶看的。因此,大部分都是簡短的提示信息。

data字段只在請求成功時纔會有數據返回的。數據類型限定爲對象或數組,當請求須要的數據爲單個對象時則傳回對象,當請求須要的數據是列表時,則爲某個對象的數組。這裏須要注意的就是,不要將data傳入字符串或數字,即便請求須要的數據只有一個,好比token,那返回的data應該爲:

// 正確 data: { token: 123456 } // 錯誤 data: 123456 

接口版本的設計

接口不可能一成不變,在不停迭代中,總會發生變化。接口的變化通常會有幾種:

  • 數據的變化,好比增長了舊版本不支持的數據類型
  • 參數的變化,好比新增了參數
  • 接口的廢棄,再也不使用該接口了

爲了適應這些變化,必須得作接口版本的設計。實現上,通常有兩種作法:

  1. 每一個接口有各自的版本,通常爲接口添加個version的參數。
  2. 整個接口系統有統一的版本,通常在URL中添加版本號,好比http://api.domain.com/v2。

大部分狀況下會採用第一種方式,當某一個接口有變更時,在這個接口上疊加版本號,併兼容舊版本。App的新版本開發傳參時則將傳入新版本的version。

若是整個接口系統的根基都發生變更的話,好比微博API,從OAuth1.0升級到OAuth2.0,整個API都進行了升級。

有時候,一個接口的變更還會影響到其餘接口,但作的時候不必定能發現。所以,最好還要有一套完善的測試機制保證每次接口變動都能測試到全部相關層面。

寫在最後

關於接口安全的設計以及架構,以及密碼學安全方面等等,我這只是給了一個實際的例子,告訴你們,我是這麼作的,有問題歡迎留言。

相關文章
相關標籤/搜索