你開放的接口真的就很安全嗎,看看有沒有做到如下幾點
1.請求身份驗證
2.請求參數校驗
3.請求是否唯一
4.請求次數限制
請求身份驗證
基于AccessKey:為接口調用放分配AccessKey和SecretKey(不參與傳輸,只用于本地接口加密,不能泄露)
基于token身份驗證:
1.用戶登錄提供認證信息(如:賬號密碼)服務器驗證成功后將用戶信息保存到token內并設置有效期,再返回token給調用方
2.調用方保存token,并在有效期內重新換取token,保證token是有效的
3.服務器驗證token有效性,無效則攔截請求返回錯誤信息,反之則從token內獲取用戶信息進行后續操作
請求參數校驗
1.校驗參數合理性(如:參數類型,參數長度,參數值校驗)
2.防止XSS,SQL注入(解決方案:過濾敏感字符或直接返回錯誤信息)
3.校驗參數可靠性是否被篡改(可以將參數以特定格式排列+秘鑰組成字符串,在進行MD5或SHA簽名)
請求是否唯一
前面第3點解決了請求參數被篡改的隱患,但是還存在著重復使用請求參數偽造二次請求的隱患
timestamp+nonce方案
nonce指唯一的隨機字符串 ,用來標識每個被簽名的請求。通過為每個請求提供一個唯一的標識符,服務器能夠防止請求被多次使用(記錄所有用過的nonce以阻止它們被二次使用)。
然而,對服務器來說永久存儲所有接收到的nonce的代價是非常大的。可以使用timestamp來優化nonce的存儲 。
假設允許客戶端和服務端最多能存在15分鐘的時間差,同時追蹤記錄在服務端的nonce集合。當有新的請求進入時,首先檢查攜帶的timestamp是否在15分鐘內,如超出時間范圍,則拒絕,然后查詢攜帶的nonce,如存在已有集合,則拒絕。否則,記錄該nonce,并刪除集合內時間戳大于15分鐘的nonce(可以使用redis的expire,新增nonce的同時設置它的超時失效時間為15分鐘)。
請求次數限制
某些資源我們需要限制用戶的請求次數,同時也為了防止非人為操作可能導致系統的崩潰
實現思路如下:
假如我們允許用戶每秒鐘最多10次請求,超過10次則返回“手速太快了,慢點把。。”
這里我們使用redis輔助我們實現:
以用戶IP為key,請求次數為value,有效時間為1秒
用戶在每秒的第一次訪問的時候,此時我們的redis是沒有key為用戶ip的數據的(因為失效了,或者第一次請求)所以我們要初始化當前請求用戶的ip為keyvalue為0到redis數據庫
當用戶在1s內再次發起請求我們就將此ip的請求次數+1,并判斷請求次數是否已近>=10
>=10則返回給用戶手速太快了!請稍后重試..否則繼續執行后續操作
具體實現代碼如下:
Boolean hasIp = redisUtil.hasKey(key);
if (!hasIp) {
//初始化ip=0
redisUtil.setEx(key, "0", 1, TimeUnit.SECONDS);
return true;
}
int reqCount = 0;
String s = redisUtil.get(key);
if (!StringUtils.isEmpty(s)) {
reqCount = Integer.parseInt(s);
}
if (reqCount >= 10) {
//請求次數大于10限制訪問
throw new ApiRRException("手速太快了!請稍后重試..");
}
//對請求次數++
redisUtil.setEx(key, (reqCount + 1) + "", 1, TimeUnit.SECONDS);