基于公网的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")) }