1.什麼是接口簽名?前端
答:接口開發是各系統之間對接的重要方式,其數據是經過開放的互聯網傳輸,對數據的安全性要有必定要求。爲了提升傳輸過程參數的防篡改性,簽名sign的方式是目前比較經常使用的方式。java
重點:請求身份是否合法?請求參數是否被惡意篡改,請求是否惟一.web
2.怎麼提供一個安全性高的接口?redis
答:算法
2.1. 請求身份:json
Appkey(公鑰)開發者標識肯定惟一,AppSecret密鑰(用於接口加密,確保生成參數不被猜想)有個缺點密鑰讓人家知道仍是完蛋了.安全
2.2. 接口加參數服務器
接口加個參數timestamp時間戳,格式爲yyyy-mm-dd HH:mm:ss,例如:2013-05-06 13:52:03(建議傳入當前時間),防止同一時間內點擊兩次.app
接口加個參數Appkey(公鑰).優化
接口加個參數sign簽名字段:簽名sign具體算法爲:根據傳入參數名稱(簽名sign除外)將全部請求參數按照首字母前後順序排序,md5(密鑰+除密鑰外排好序的參數串+密鑰)後轉換爲大寫字母,注意編碼,統一爲utf8。注意要有AppSecret密鑰.
相似下面這個樣子:
method=xx
&appkey=xx
×tamp=2014-12-26 10:27:26
&format=json
&sign=生成的簽名
以上兩步,解決了防止防止篡改,參數正確,可是沒有解決着重複請求參數僞造二次請求的隱患。也就是重放攻擊。
2.3.timestamp+nonce方案
nonce指惟一的隨機字符串,用來標識每一個被簽名的請求。經過爲每一個請求提供一個惟一的標識符,服務器可以防止請求被屢次使用(記錄全部用過的nonce以阻止它們被二次使用)。
然而,對服務器來講永久存儲全部接收到的nonce的代價是很是大的。可使用timestamp來優化nonce的存儲。
假設容許客戶端和服務端最多能存在6分鐘的時間差,同時追蹤記錄在服務端的nonce集合。當有新的請求進入時,首先檢查攜帶的timestamp是否在6分鐘內,如超出時間範圍,則拒絕,而後查詢攜帶的nonce,如存在已有集合,則拒絕。不然,記錄該nonce,並刪除集合內時間戳大於6分鐘的nonce(可使用redis的expire,新增nonce的同時設置它的超時失效時間爲6分鐘)。
另外除了公鑰密鑰,還能夠用token身份驗證。
服務端驗證帳號密碼,生成token,存儲30分鐘,token發給前端,前端每次請求帶上這個token。可是仍然存在着安全隱患,token被劫持,僞造請求和篡改參數。
解決方法:Token+(AppKey參數加密),即便Token被劫持,對方不知道AppKey和簽名算法,就沒法僞造請求和篡改參數。再結合上述的重發攻擊解決方案,即便請求參數被劫持也沒法僞造二次重複請求。
系統能夠設定一些規則:
還有就是排序參數,若是是隻調用web接口不超過3個,建議不要寫字母排序方法,浪費時間.
下面提供md5utils類:
使用: MD5Utils.MD5Encode(str,"utf8");
import java.security.MessageDigest;
public class MD5Utils {
private static final String hexDigIts[] = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f"};
/**
* MD5加密
*
* @param origin 字符
* @param charsetname 編碼
* @return
*/
public static String MD5Encode(String origin, String charsetname) {
String resultString = null;
try {
resultString = new String(origin);
MessageDigest md = MessageDigest.getInstance("MD5");
if (null == charsetname || "".equals(charsetname)) {
resultString = byteArrayToHexString(md.digest(resultString.getBytes()));
} else {
resultString = byteArrayToHexString(md.digest(resultString.getBytes(charsetname)));
}
} catch (Exception e) {
}
return resultString;
}
public static String byteArrayToHexString(byte b[]) {
StringBuffer resultSb = new StringBuffer();
for (int i = 0; i < b.length; i++) {
resultSb.append(byteToHexString(b[i]));
}
return resultSb.toString();
}
public static String byteToHexString(byte b) {
int n = b;
if (n < 0) {
n += 256;
}
int d1 = n / 16;
int d2 = n % 16;
return hexDigIts[d1] + hexDigIts[d2];
}
}
另外相同的參數,相同的接口重複的調用,能夠直接返回:
{
"code": -1,
"msg": "調用頻率太過頻繁"
}
雖然有些攻擊仍是防不到,可是能讓你裝裝逼,讓客戶看到哇,我此次選的系統接口,很專業。(確實,讓我訪問接口每訪問一次都要加簽名什麼的,搞得我很難受。)
內容借鑑:(簡書做者:Joker_Coding,連接:https://www.jianshu.com/p/ad410836587a)