iOS 报文校验及字符串排序

最近维护了一个几年前的老项目,这个项目的APP早期因为工期很紧(12天完工),所以在设计之处压根就没有考虑和使用https。所以最近系统经常被黑。。。

最开始,对方使用的手段是直接抓取报文,脱离APP,直接使用这段报文在短时间内并发N条给服务器,这时候服务器就懵逼了,直接给处理N次(比如说签到领奖励接口...)

后来这个BUG处理完了以后,对方又开始发力了。。。把服务器返回的报文给篡改了:这个报文是登陆以后,服务器返回的身份数据。比如说你登录成功了,服务器把你的手机号码返回给了APP,这时候对方把这个号码篡改为他的手机号,也就是说,你后面做的一系列操作都是在帮他在做:签到?订购?。。。细思极恐。

这会,又开始填坑了。。。给出的方案是对报文进行校验:

后台与APP端约定一个KEY: V_SIGNDATA_KEY @"xxxx@2017~2050"

每个接口返回v_signData = 4B451F50359639270599C90356398563

APP端做的处理如下:

1、获取v_signData:

NSString *v_signData= [respDic objectForKey:@"v_signData"];

2、data转json字符串:(先判断是不是字典)

NSString *contentData=[[respObj objectForKey:@"data"]isKindOfClass:[NSDictionary class]]?[self dictionaryToJson:[respObj objectForKey:@"data"]]:[respDic objectForKey:@"data"];

3、计算contentData+V_SIGNDATA_KEY的字符排序后32位大写MD5值

 NSString *Md5Str=[self md532BitUpper:[self handleStringSortWithStr:[NSString stringWithFormat:@"%@%@",contentData,V_SIGNDATA_KEY]]];

4、判断

[v_signData isEqualToString:[self md532BitUpper:[self handleStringSortWithStr:V_SIGNDATA_KEY]]]

===>若果v_signData和V_SIGNDATA_KEY的字符排序后32位大写MD5值相符,非特定对象通过验证

[v_signData isEqualToString:Md5Str]

===>v_signData和contentData+V_SIGNDATA_KEY的字符排序后32位大写MD5值相符,通过验证

其他不通过。

------------------------------------------------------------割------------------------------------------------------------------

这里主要是说一下,为什么要做字符排序。。。这特么是一个坑

在没做字符排序之前,服务端的data字典和APP收到的data字典虽然字段内容全部相同,但是字段排序变了。。。

所以直接把data字典转json字符串的话,不管怎么验证特么都会不对。

再后来方案是给data转换的json字符串做字符排序。。这样只要不被篡改,不管字段排序怎么变,字符排序是不会变的.举个例子:

lldbz@2017~2050字符排序以后的结果是:00012257@bdllz~

这样算是解决了这个问题吧..........

------------------------------------------------------------割------------------------------------------------------------------

下面是几个字符串处理用到的方法:

//字典转为Json字符串

-(NSString *)dictionaryToJson:(NSDictionary *)dic

{

    NSError *error = nil;

    NSData *jsonData = [NSJSONSerialization dataWithJSONObject:dic options:NSJSONWritingPrettyPrinted error:&error];

    return [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];

}

//字符串排序去空格换行

-(NSString *)handleStringSortWithStr:(NSString *)str

{

    str = [str stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]; //去除掉首尾的空白字符和换行字符

    str = [str stringByReplacingOccurrencesOfString:@"\r" withString:@""];

    str = [str stringByReplacingOccurrencesOfString:@"\n" withString:@""];

    str = [str stringByReplacingOccurrencesOfString:@"\t" withString:@""];

    str = [str stringByReplacingOccurrencesOfString:@"\\s" withString:@""];

    str = [str stringByReplacingOccurrencesOfString:@" " withString:@""];

    str = [str stringByReplacingOccurrencesOfString:@"\\" withString:@""];

    NSMutableArray *array=[[NSMutableArray alloc]initWithCapacity:0];

    for (int i=0; i<str.length; i++)

    {

        NSRange ange={i,1};

        NSString* singleStr=[str substringWithRange:ange];

        [array addObject:singleStr];

    }

    NSArray *sortedArray = [array sortedArrayUsingSelector:@selector(compare:)];

    NSString *resultStr = [sortedArray componentsJoinedByString:@""];

    return resultStr;

}

//MD5 32位大写加密

- (NSString*)md532BitUpper:(NSString*)password

{

    const char *cStr = [password UTF8String];

    unsigned char result[16];

    NSNumber *num = [NSNumber numberWithUnsignedLong:strlen(cStr)];

    CC_MD5( cStr,[num intValue], result );

    return [[NSString stringWithFormat:

             @"%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X",

             result[0], result[1], result[2], result[3],

             result[4], result[5], result[6], result[7],

             result[8], result[9], result[10], result[11],

             result[12], result[13], result[14], result[15]

             ] uppercaseString];

}

相关推荐

发表评论

电子邮件地址不会被公开。

微信扫一扫,分享到朋友圈

iOS 报文校验及字符串排序
返回顶部

显示

忘记密码?

显示

显示

获取验证码

Close