天天看點

如何設計一個安全的對外接口?

最近有個項目需要對外提供一個接口,提供公網域名進行通路,而且接口和交易訂單有關,是以安全性很重要;這裡整理了一下常用的一些安全措施以及具體如何去實作。

安全措施

個人覺得安全措施大體來看主要在兩個方面,一方面就是如何保證資料在傳輸過程中的安全性,另一個方面是資料已經到達伺服器端,伺服器端如何識别資料,如何不被攻擊;

下面具體看看都有哪些安全措施。

###

1 資料加密

我們知道資料在傳輸過程中是很容易被抓包的,如果直接傳輸比如通過http協定,那麼使用者傳輸的資料可以被任何人擷取,是以必須對資料加密。

常見的做法對關鍵字段加密比如使用者密碼直接通過md5加密;現在主流的做法是使用https協定,在http和tcp之間添加一層加密層(SSL層),這一層負責資料的加密和解密;

2.資料加簽

資料加簽就是由發送者産生一段無法僞造的一段數字串,來保證資料在傳輸過程中不被篡改;你可能會問資料如果已經通過https加密了,還有必要進行加簽嗎?

資料在傳輸過程中經過加密,理論上就算被抓包,也無法對資料進行篡改;但是我們要知道加密的部分其實隻是在外網,現在很多服務在内網中都需要經過很多服務跳轉,是以這裡的加簽可以防止内網中資料被篡改;

3. 時間戳機制

資料是很容易被抓包的,但是經過如上的加密,加簽處理,就算拿到資料也不能看到真實的資料;但是有不法者不關心真實的資料,而是直接拿到抓取的資料包進行惡意請求。

這時候可以使用時間戳機制,在每次請求中加入目前的時間,伺服器端會拿到目前時間和消息中的時間相減,看看是否在一個固定的時間範圍内比如5分鐘内;這樣惡意請求的資料包是無法更改裡面時間的,是以5分鐘後就視為非法請求了;

4. AppId機制

大部分網站基本都需要使用者名和密碼才能登入,并不是誰來能使用我的網站,這其實也是一種安全機制。

### 對應的對外提供的接口其實也需要這麼一種機制,并不是誰都可以調用,需要使用接口的使用者需要在背景開通appid,提供給使用者相關的密鑰;在調用的接口中需要提供appid+密鑰,伺服器端會進行相關的驗證;

5. 限流機制

本來就是真實的使用者,并且開通了appid,但是出現頻繁調用接口的情況;這種情況需要給相關appid限流處理,常用的限流算法有令牌桶和漏桶算法;

6. 黑名單機制

如果此appid進行過很多非法操作,或者說專門有一個中黑系統,經過分析之後直接将此appid列入黑名單,所有請求直接傳回錯誤碼;

7. 資料合法性校驗

這個可以說是每個系統都會有的處理機制,隻有在資料是合法的情況下才會進行資料處理;每個系統都有自己的驗證規則,當然也可能有一些正常性的規則,比如身份證長度群組成,電話号碼長度群組成等等;

如何實作

以上大體介紹了一下常用的一些接口安全措施,當然可能還有其他我不知道的方式,希望大家補充,下面看看以上這些方法措施,具體如何實作;

1. 資料加密

現在主流的加密方式有對稱加密和非對稱加密;大家也可以閱讀下《使用者密碼怎麼加密存儲?》這篇文章。

對稱加密:對稱密鑰在加密和解密的過程中使用的密鑰是相同的,常見的對稱加密算法有DES,AES;優點是計算速度快,缺點是在資料傳送前,發送方和接收方必須商定好秘鑰,然後使雙方都能儲存好秘鑰,如果一方的秘鑰被洩露,那麼加密資訊也就不安全了;

非對稱加密:服務端會生成一對密鑰,私鑰存放在伺服器端,公鑰可以釋出給任何人使用;優點就是比起對稱加密更加安全,但是加解密的速度比對稱加密慢太多了;廣泛使用的是RSA算法;

兩種方式各有優缺點,而https的實作方式正好是結合了兩種加密方式,整合了雙方的優點,在安全和性能方面都比較好;

對稱加密和非對稱加密代碼實作,jdk提供了相關的工具類可以直接使用,此處不過多介紹;關于https如何配置使用相對來說複雜一些,可以參考之前分享的文章,關注微信公衆号:Java技術棧,可以在菜單中擷取我整理的 N 篇 HTTP 教程,都是幹貨。

2. 資料加簽

資料簽名使用比較多的是md5算法,将需要送出的資料通過某種方式組合和一個字元串,然後通過md5生成一段加密字元串,這段加密字元串就是資料包的簽名,可以看一個簡單的例子:

str:參數1={參數1}&參數2={參數2}&……&參數n={參數n}$key={使用者密鑰};
MD5.encrypt(str);      

注意最後的使用者密鑰,用戶端和服務端都有一份,這樣會更加安全;

解密後的資料,經過簽名認證後,我們拿到資料包中的用戶端時間戳字段,然後用伺服器目前時間去減用戶端時間,看結果是否在一個區間内,僞代碼如下:

long interval=5*60*1000;//逾時時間
long clientTime=request.getparameter("clientTime");
long serverTime=System.currentTimeMillis();
if(serverTime-clientTime>interval){
    return new Response("超過處理時長")
}      

生成一個唯一的AppId即可,密鑰使用字母、數字等特殊字元随機生成即可;生成唯一AppId根據實際情況看是否需要全局唯一;但是不管是否全局唯一最好讓生成的Id有如下屬性:

趨勢遞增:這樣在儲存資料庫的時候,使用索引性能更好; 資訊安全:盡量不要連續的,容易發現規律;

關于全局唯一Id生成的方式常見的有類snowflake方式等;

常用的限流算法包括:令牌桶限流,漏桶限流,計數器限流;具體也可以看下《漏桶算法&令牌桶算法》這篇文章。

1.令牌桶限流

令牌桶算法的原理是系統以一定速率向桶中放入令牌,填滿了就丢棄令牌;請求來時會先從桶中取出令牌,如果能取到令牌,則可以繼續完成請求,否則等待或者拒絕服務;令牌桶允許一定程度突發流量,隻要有令牌就可以處理,支援一次拿多個令牌;

2.漏桶限流

漏桶算法的原理是按照固定常量速率流出請求,流入請求速率任意,當請求數超過桶的容量時,新的請求等待或者拒絕服務;可以看出漏桶算法可以強制限制資料的傳輸速度;

3.計數器限流

計數器是一種比較簡單粗暴的算法,主要用來限制總并發數,比如資料庫連接配接池、線程池、秒殺的并發數;計數器限流隻要一定時間内的總請求數超過設定的閥值則進行限流;

具體基于以上算法如何實作,Guava提供了RateLimiter工具類基于基于令牌桶算法:

RateLimiter rateLimiter = RateLimiter.create(5);      

以上代碼表示一秒鐘隻允許處理五個并發請求,以上方式隻能用在單應用的請求限流,不能進行全局限流;這個時候就需要分布式限流,可以基于redis+lua來實作;

如何為什麼中黑我們這邊不讨論,我們可以給每個使用者設定一個狀态比如包括:初始化狀态,正常狀态,中黑狀态,關閉狀态等等;或者我們直接通過分布式配置中心,直接儲存黑名單清單,每次檢查是否在清單中即可;

合法性校驗包括:正常性校驗以及業務校驗; 正常性校驗:包括簽名校驗,必填校驗,長度校驗,類型校驗,格式校驗等; 業務校驗:根據實際業務而定,比如訂單金額不能小于0等;

總結

本文大緻列舉了幾種常見的安全措施機制包括:資料加密、資料加簽、時間戳機制、AppId機制、限流機制、黑名單機制以及資料合法性校驗;當然肯定有其他方式,歡迎補充。