在很多请求中经常会看到sign这个参数,今天就一个具体例子讲述最简单最基础也是比较常见的加密情形
先看下这次请求的url:https://api.xnqdapp.com/xnqd/app/order/queryOrderList.json?currentTime=请求时的时间戳&phoneType=手机型号&appVersion=2.4.0&pageIndex=0&phoneSystem=A&appName=creditSteward&pageSize=10&location=你的地址(比如上海市)&deviceId=手机id&version=2.4.0&appChannel=手机品牌&phoneVersion=9
我要是直接拿这个url请求他会返回错误信息{"result":{"appName":"xnqd","code":"600000","message":"对不起,签名验证错误","status":"error","success":false}}
我根本就没提交和签名有关的信息。。去请求头部找一下 发现有个叫_nsign的参数,应该就是它了 毕竟sign=签名我还是知道的。
平时见到的sign一般都是在post参数或者get请求中,这次来了个新花样,放到了请求头部中。这个长度一看就知道32位!
之前做过类似的关于sign的爬虫,最最最简单的sign加密方式就是根据请求参数的字典先按照key排序,然后在用& =符号拼接在一起组成长字符串再来个md5就完事了。我凭着这份经验(懒)尝试了一下,果然失败了。猜测很有可能长字符串被加盐了。只能apk反编译看看代码了
先下载一个apk,在来一个反编译大哥jadx-gui(不会用的去百度吧)
反编译之后直接搜索_nsign,找到这一行
requestHeaders.put("_nsign", MD5Utils.a(hashMap, ConstantUtils.singKey));
hashmap应该就是我们的请求参数的字典然后去MD5Utils.a看看吧
public static String a(Map<String, Object> map, String str) throws UnsupportedEncodingException {
if (map == null) {
map = new HashMap();
}
Object[] toArray = map.keySet().toArray();
Arrays.sort(toArray);
StringBuffer stringBuffer = new StringBuffer();
Object obj = 1;
for (Object obj2 : toArray) {
if (obj != null) {
obj = null;
} else {
stringBuffer.append(HttpUtils.PARAMETERS_SEPARATOR);
}
stringBuffer.append(obj2).append(HttpUtils.EQUAL_SIGN);
Object obj3 = map.get(obj2);
String str2 = "";
if (obj3 != null) {
str2 = String.valueOf(obj3).replaceAll(" ", "");
}
stringBuffer.append(str2);
}
stringBuffer.append("&v__s_k_=" + str);
return a(stringBuffer.toString()).toUpperCase();
看到倒数第二行我就开心了 果然加盐了,其中用了很多常量看起来很唬人,其实在反编译代码里面搜一搜就全出来啦比如HttpUtils.PARAMETERS_SEPARATOR其实就是&,HttpUtils.EQUAL_SIGN就是=,倒数第二行stringBuffer.append("&v__s_k_=" + str),这个str就是传入的第二个参数ConstantUtils.singKey也是个常量。迫不及待了,其实和我上面想的差不多就是加了盐导致md5稍微变了样
其实最终的长字符串类似这样:appChannel=xiaomi&appName=creditSteward&appVersion=2.4.0¤tTime=时间戳&deviceId=手机id&location=上海市&pageIndex=1&pageSize=20&phoneSystem=A&phoneType=手机型号&phoneVersion=9&version=2.4.0&v__s_k_=xinyong234@21@#$fasd
给他md5加密一下在转为大写,得到了我们想要的_nsign。把签名加入请求头部之后再去请求一下。
{"result":{"message":"请求成功","appName":"xnqd","status":"success","success":true}...
成功啦。这个sign加密比较简单,重点应该在反编译apk后查询代码(虽然我根本没教)~~~~~