基於公網的http協議的請求/響應時不安全的,存在被截獲,篡改,重發的可能。算法
防假裝攻擊(如:公網,第三方有意或惡意的調用接口);api
防篡改攻擊(如:公網,請求頭/查詢字符串/內容,在傳輸過程當中被篡改);數組
防重發攻擊(如:公網,請求被截獲,稍後被重發屢次);安全
防數據信息泄露(如:截獲用戶請求,截獲到帳號,密碼等);服務器
基於HTTP協議的接口(通用數據交互接口)須要知足前三條要求(主要經過時間戳和簽名),第四條採用HTTPS協議或傳輸內容使用非對稱加密(用在用戶登陸,受權,解密接口)。app
經過簽名,IP白名單搞定。工具
輕量級;測試
適合於異構系統(跨操做系統,多語言簡易實現);ui
易於開發;編碼
易於測試;
易於部署;
知足接口安全要求,無過分設計;
對除簽名外的全部請求參數按key作升序排列,value無需編碼, (假設當前時間的時間戳是12345678) 例如:有c=3,b=2,a=1 三個參,另加上時間戳後, 按key排序後爲:a=1,b=2,c=3,_timestamp=12345678。 ;
把參數名和參數值連接組成字符串, a1b2c3_timestamp12345678;
用申請獲得的appkey連接到拼接字符串的頭部和尾部,而後進行32位md5加密,最後獲得md5加密摘要轉換成大寫, 示例:假設appkey=test,md5(testa1b2c3_timestamp12345678test),取得MD5摘要值 C5F3EB5D7DC2748AED89E90AF00081E6 。 ;
/** * Description * 簽名工具 * * @author Mr. Chun. */ public class SignBuilder { /** * 生成簽名結果 * * @param sArray 要簽名的數組 * @return 簽名結果字符串 */ public static String buildMysign(Map<String, String> sArray, String secret) { String prestr = createLinkString(sArray); //把數組全部元素,按照「參數=參數值」的模式用「&」字符拼接成字符串 prestr = secret+ prestr + secret; //把拼接後的字符串再與安全校驗碼直接鏈接起來 String mysign; try { mysign = DigestUtils.md5Hex(prestr.getBytes("UTF-8")); } catch (UnsupportedEncodingException e) { throw new RuntimeException("MD5簽名過程當中出現錯誤,指定的編碼集錯誤"); } return mysign; } /** * 除去數組中的空值和簽名參數 * * @param sArray 簽名參數組 * @return 去掉空值與簽名參數後的新簽名參數組 */ private static Map<String, String> paraFilter(Map<String, String> sArray) { Map<String, String> result = new HashMap<String, String>(); if (sArray == null || sArray.size() <= 0) { return result; } for (String key : sArray.keySet()) { String value = sArray.get(key); if (value == null || value.equals("") || key.equalsIgnoreCase("sign") || key.equalsIgnoreCase("mobileDevice") || key.equals("v")) { continue; } result.put(key, value); } return result; } /** * 把數組全部元素排序,並按照「參數=參數值」的模式用「&」字符拼接成字符串 * * @param params 須要排序並參與字符拼接的參數組 * @return 拼接後字符串 */ public static String createLinkString(Map<String, String> params) { params = paraFilter(params); List<String> keys = new ArrayList<String>(params.keySet()); Collections.sort(keys); String prestr = ""; for (int i = 0; i < keys.size(); i++) { String key = keys.get(i); String value = params.get(key); // if (i == keys.size() - 1) {//拼接時,不包括最後一個&字符 // prestr = prestr + key + "=" + value; // } else { // prestr = prestr + key + "=" + value + "&"; // } prestr = prestr + key + value; } return prestr; } /** * 作map的轉換 * * @param parameterMap * @return */ public static Map<String, String> convertRequestMap(Map<String, String[]> parameterMap) { Map<String, String> alipayParameter = new HashMap<String, String>(); for (Iterator<String> iter = parameterMap.keySet().iterator(); iter.hasNext(); ) { String name = (String) iter.next(); String[] values = parameterMap.get(name); String valueStr = ""; for (int i = 0; i < values.length; i++) { valueStr = (i == values.length - 1) ? valueStr + values[i] : valueStr + values[i] + ","; } alipayParameter.put(name, valueStr); } return alipayParameter; } }
Go代碼
package main import ( "bytes" "crypto/hmac" "crypto/sha256" "encoding/base64" "fmt" "net/url" "sort" "time" ) // Signature used to generate signature with the appsecret/method/params/RequestURI func Signature(appsecret, method string, params url.Values, RequestURL string) (result string) { var b bytes.Buffer keys := make([]string, len(params)) pa := make(map[string]string) for k, v := range params { pa[k] = v[0] keys = append(keys, k) } sort.Strings(keys) for _, key := range keys { if key == "_signature" { continue } val := pa[key] if key != "" && val != "" { b.WriteString(key) b.WriteString(val) } } stringToSign := fmt.Sprintf("%v\n%v\n%v\n", method, b.String(), RequestURL) fmt.Println(stringToSign) sha256 := sha256.New hash := hmac.New(sha256, []byte(appsecret)) hash.Write([]byte(stringToSign)) return base64.StdEncoding.EncodeToString(hash.Sum(nil)) } func main() { //http://xxx:8091/v2api/dv/filter?_appid=test&_signature=sdfdf&_timestamp=2017-11-09%2019%3A39%3A00&_index=app_service_homework_miniactivefinish_di&_type=app_service_homework_miniactivefinish_di&_size=10&_from=0 appsecret := "bigdatawmw" method := "GET" RequestURL := "/v2api/dv/filter" params := make(url.Values) params.Add("_appid", "bigdata") params.Add("_timestamp", time.Now().Format("2006-01-02 15:04:05")) params.Add("_index", "app_service_superbook_packorder_da") params.Add("_type", "app_service_superbook_packorder_da") params.Add("_size", "10") params.Add("_from", "0") fmt.Println("http://xxx:8091" + RequestURL + "?" + params.Encode() + "&_signature=" + Signature(appsecret, method, params, RequestURL)) //signature := "mFdpvLh48ca4mDVEItE9++AKKQ/IVca7O/ZyyB8hR58=" // fmt.Println(Signature(appsecret, method, params, RequestURL)) fmt.Println(time.Now().Format("2006-01-02 15:04:05")) }