(辦公)接口簽名的思考

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密鑰.

相似下面這個樣子:

      http://xxxx?

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(可使用redisexpire,新增nonce的同時設置它的超時失效時間爲6分鐘)。

 

   另外除了公鑰密鑰,還能夠用token身份驗證。

   服務端驗證帳號密碼,生成token,存儲30分鐘,token發給前端,前端每次請求帶上這個token。可是仍然存在着安全隱患,token被劫持,僞造請求和篡改參數。

  解決方法:Token+(AppKey參數加密),即便Token被劫持,對方不知道AppKey和簽名算法,就沒法僞造請求和篡改參數。再結合上述的重發攻擊解決方案,即便請求參數被劫持也沒法僞造二次重複請求。

 

系統能夠設定一些規則:

  1. 公鑰密鑰有本身的系統生成.
  2. 接口有效性6分鐘.
  3. 接口調用頻率:1毫秒以上.
  4. 數據參數安全,驗證簽名.
  5. 具體算法爲:根據傳入參數名稱(簽名sign除外)將全部請求參數按照首字母前後順序排序,md5(密鑰+除密鑰外排好序的參數串+密鑰)後轉換爲大寫字母。

   還有就是排序參數,若是是隻調用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)

相關文章
相關標籤/搜索