iOS mobile terminal interface encryption process (including single sign-on and expiration time)

iOS mobile terminal interface encryption process (including single sign-on and expiration time)

I recently changed jobs, and a set of interview questions in the new company was about the mobile terminal interface encryption process. At that time, I drew a rough UML class diagram based on the interview questions, but there were still many things that were not considered carefully. After getting in touch with the code and carefully studying the data request logic, I felt that it was necessary to summarize it to deepen my understanding.

[[213149]]

  • For data security, most companies that do not use https will choose tokens to improve the security of data requests. The methods of generating tokens are also different, as long as the uniqueness is guaranteed. The best is the background management token, which is generated by the background and returned to the front end for storage.

Send Parameters

All interfaces need to carry the current version number and platform

Different app_id and private_key are assigned to iOS and Android. In addition to the above data, timestamp, app_id, private_key, rand, and sign are also sent for each communication. See the table below:

For example: iOS

  1. app_id=170ib799dd511e7b66000163e033322  
  2. private_key = 170ib799dd511e7b66000163e033322

Business data is phoneNo=123456&password=123456

The data sent without sign is:

  1. app_id=170ib799dd511e7b66000163e033322&phoneNo=123456& password =123456&plat=iOS&rand=12dwfhdy487rSelsd×tamp=2017-12-9-13:39:39:01&ver=1.0

sign = MD5(data + private_key), which is to perform MD5 operation on the string

  1. app_id=170ib799dd511e7b66000163e033322&phoneNo=123456& password =123456&private_key=170ib799dd511e7b66000163e033322&plat=iOS&rand=12dwfhdy487rSelsd×tamp=2017-12-9-13:39:39:01&ver=1.0

The calculated result sign is finally a 32-bit data and letter combination 8357heukf384r83gh3fi3dwks42i993 (example)

Finally, data + sign is sent, such as:

  1. app_id=170ib799dd511e7b66000163e033322&phoneNo=123456& password =123456&plat=iOS&rand=12dwfhdy487rSelsd×tamp=2017-12-9-13:39:39:01&ver=1.0&sign= 8357heukf384r83gh3fi3dwks42i993

This is the signature management class.h code

  1. #import <Foundation/Foundation.h>
  2.  
  3. @interface TPBaseRequest : NSObject
  4.  
  5. @property (nonatomic, strong) NSString *plat;
  6. @property (nonatomic, strong) NSString *ver;
  7.  
  8. - (NSDictionary *)baseParameters;
  9. - (NSDictionary *)finalParametersFrom:(NSDictionary *)dic;
  10.  
  11. @ end  
  12.  
  13.  
  14. Author: Qingqing is the boss, so listen to her
  15. Link: http://www.jianshu.com/p/fe3c2931ed53
  16. Source: Jianshu
  17. The copyright belongs to the author. For commercial reproduction, please contact the author for authorization. For non-commercial reproduction, please indicate the source.

This is the signature management class.m code

  1. #import "TPBaseRequest.h"  
  2. #import <CommonCrypto/CommonDigest.h>
  3.  
  4. @interface TPBaseRequest()
  5.  
  6. @property (nonatomic, strong)NSString *rand;
  7.  
  8. @property (nonatomic, copy) NSString *timeStr;
  9.  
  10. @ end  
  11.  
  12. @implementation TPBaseRequest
  13.  
  14. //The final output is data(base + dic)+sign
  15. - (NSDictionary *)finalParametersFrom:(NSDictionary *)dic
  16. {
  17. self.rand = [self gainRand];
  18. NSMutableDictionary *finalDic = [NSMutableDictionary dictionaryWithDictionary:[self baseParameters]];
  19. [finalDic removeObjectForKey:@ "private_key" ];
  20. [finalDic addEntriesFromDictionary:dic];
  21. [finalDic setObject:[self gainSign:dic] forKey:@ "sign" ];
  22. [finalDic setObject:_timeStr forKey:@ "timestamp" ];
  23. return finalDic;
  24. }
  25. //Basic parameters
  26. - (NSDictionary *)baseParameters
  27. {
  28. //Basic parameter assignment
  29. NSMutableDictionary *para = [NSMutableDictionary dictionary];
  30. [para setObject:kApp_id forKey:@ "app_id" ];
  31. [para setObject:kPrivate_key forKey:@ "private_key" ];
  32. [para setObject:@ "ios" forKey:@ "plat" ];
  33. [para setObject:[[[NSBundle mainBundle] infoDictionary] objectForKey:@ "CFBundleShortVersionString" ] forKey:@ "ver" ];
  34. [para setObject:self.rand forKey:@ "rand" ];
  35. [para setObject:[self gainTimestamp] forKey:@ "timestamp" ];
  36.      
  37. if([MDAccountStore isLogined]){
  38. if(![MDAccountManager sharedInstance].currentAccount){
  39. [MDAccountManager sharedInstance].currentAccount = [[MDAccountStore sharedInstance] readTheAccount];
  40. }
  41. }
  42. // Check if there is a user logged in. If yes, carry userId
  43. if ([MDAccountManager sharedInstance].currentAccount.userId) {
  44. long userId = [MDAccountManager sharedInstance].currentAccount.userId;
  45. [para setObject:[NSNumber numberWithLong:userId] forKey:@ "userId" ];
  46. }
  47. // Check if there is a token in local storage
  48. if ([MDAccountManager sharedInstance].currentAccount.token) {
  49. [para setObject:[MDAccountManager sharedInstance].currentAccount.token forKey:@ "token" ];
  50. }
  51.      
  52. return [NSDictionary dictionaryWithDictionary:para];
  53. }
  54. //Get a random number
  55. - (NSString *)gainRand
  56. {
  57. NSString *str = [NSString string];
  58. //16 bits
  59. for ( int i = 0; i < 16; i++)
  60. {
  61. // Random letters and numbers
  62. switch(arc4random() % 3) {
  63. case 0:
  64. str = [str stringByAppendingString:[NSString stringWithFormat:@ "%d" , arc4random() % 10]];
  65. break;
  66. case 1:
  67. str = [str stringByAppendingString:[NSString stringWithFormat:@ "%c" , (arc4random() % 26) + 97]];
  68. break;
  69. case 2:
  70. str = [str stringByAppendingString:[NSString stringWithFormat:@ "%c" , (arc4random() % 26) + 65]];
  71. break;
  72. }
  73. }
  74. return str;
  75. }
  76. //Get the time string
  77. - (NSString *)gainTimestamp
  78. {
  79. NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
  80. dateFormatter.dateFormat = @ "yyyy-MM-dd-HH:mm:ss" ;
  81. NSString *timeStr = [dateFormatter stringFromDate:[NSDate date ]];
  82. // NSString *stamp = [NSString stringWithFormat:@ "%ld" , (long)[[NSDate date ] timeIntervalSince1970]];
  83. return timeStr;
  84. }
  85. //Get the sign sign=md5(data+private_key)
  86. - (NSString *)gainSign:(NSDictionary *)dic
  87. {
  88. NSString *sign = [self getMd5_32Bit_String:[self gainData:dic]];
  89. return sign;
  90. }
  91. //Get data+private_key (private_key is included in base)
  92. - (NSString *)gainData:(NSDictionary *)dic
  93. {
  94. //data = base + dic
  95. NSMutableDictionary *basePara = [NSMutableDictionary dictionaryWithDictionary:[self baseParameters]];
  96. _timeStr = [self gainTimestamp];
  97. [basePara addEntriesFromDictionary:dic];
  98.      
  99. NSArray *arr = [basePara allKeys];
  100. arr = [arr sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2){
  101. NSComparisonResult result = [obj1 compare:obj2];
  102. return result == NSOrderedDescending;
  103. }];
  104.      
  105. NSString *dataStr = [NSString string];
  106. for ( int i = 0; i < arr. count ; i++) {
  107. dataStr = [dataStr stringByAppendingString:arr[i]];
  108. dataStr = [dataStr stringByAppendingString:@ "=" ];
  109. dataStr = [dataStr stringByAppendingString:[NSString stringWithFormat:@ "%@" ,[basePara objectOrNilForKey:arr[i]]]];
  110. dataStr = [dataStr stringByAppendingString:@ "&" ];
  111. }
  112. dataStr = [dataStr substringToIndex:dataStr.length - 1];
  113. return dataStr;
  114. }
  115. //md5 encryption
  116. - (NSString *)getMd5_32Bit_String:(NSString *)srcString
  117. {
  118. const char *cStr = [srcString UTF8String];
  119. unsigned char digest[CC_MD5_DIGEST_LENGTH];
  120. CC_MD5( cStr, strlen(cStr), digest );
  121. NSMutableString *result = [NSMutableString stringWithCapacity:CC_MD5_DIGEST_LENGTH * 2];
  122. for ( int i = 0; i < CC_MD5_DIGEST_LENGTH; i++)
  123. [result appendFormat:@ "%02x" , digest[i]];
  124.      
  125. return result;
  126. }
  127. @ end  
  128.  
  129.  
  130. Author: Qingqing is the boss, so listen to her
  131. Link: http://www.jianshu.com/p/fe3c2931ed53
  132. Source: Jianshu
  133. The copyright belongs to the author. For commercial reproduction, please contact the author for authorization. For non-commercial reproduction, please indicate the source.

After receiving the data, the background will first perform a signature verification operation to verify whether the signature is correct and whether the signature is invalid.

  • Single sign-on: If the account is logged in by another client, the token sent will change, the previous token will expire, and a login box will pop up when the client sends a data request.
  • Expiration time: The time for backend token verification. If the time exceeds the preset time, -100 will be returned.

The json data returned by single sign-on and expiration time is as follows:

  1. {
  2. "err" :{
  3. "code" :-100,
  4. "msg" : Login has expired, please log in again.
  5. "eventId" : "xxx-xxx-xxx-xxx-xxx"  
  6. }
  7. }
  • Here is a suggestion. We can set a notification listener in the root view. When we receive code = -100 when processing data, it is a login notification, and the login page is displayed modally.
  • Data Request Method

  1. + (void)postRequestWihtUrl:(NSString *)url params:(NSDictionary *)params success:(void (^)(id))successInfo failure:(TPErrorInfo)errorInfo {
  2. AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
  3. manager.requestSerializer = [AFHTTPRequestSerializer serializer];
  4. manager.responseSerializer.acceptableContentTypes = [NSSet setWithArray:@[@ "text/html" , @ "application/json" , @ "application/x-www-form-urlencoded" ]];
  5.      
  6. /**
  7. Data Request
  8. Get basic send parameters
  9. [[[TPBaseRequest alloc] init] finalParametersFrom:params]
  10. */
  11. [manager POST:url parameters:[[[TPBaseRequest alloc] init] finalParametersFrom:params] progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
  12. TPErrorHandle *err = [[TPErrorHandle alloc] initWithDic:[responseObject objectForKey:@ "err" ]];
  13. if (err.isError) {
  14. errorInfo(err);
  15. return ;
  16. }
  17. successInfo(responseObject);
  18. } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
  19. NSLog(@ "Request failed information: %@" , error);
  20. NSDictionary *errDic=error.userInfo;
  21. NSHTTPURLResponse *response=[errDic objectForKey:@ "com.alamofire.serialization.response.error.response" ];
  22. NSInteger errCode=response.statusCode;
  23. MDErrorInfo *err = [[MDErrorInfo alloc] initWithDefault];
  24. err.code = errCode;
  25. if (error.code == -1009) {
  26. err.msg = @ "Network timeout" ;
  27. }
  28. else if (err.code == 404){
  29. err.msg = @ "The network page does not exist" ;
  30. }
  31. //The method I use to issue a notification to handle errors is in the TPErrorHandle file
  32. errorInfo([[TPErrorHandle alloc] initWithMDErrorInfo:err]);
  33. }];
  34. }
  35.  
  36.  
  37. Author: Qingqing is the boss, so listen to her
  38. Link: http://www.jianshu.com/p/fe3c2931ed53
  39. Source: Jianshu
  40. The copyright belongs to the author. For commercial reproduction, please contact the author for authorization. For non-commercial reproduction, please indicate the source.
  • There is an eventId field here. I mentioned before that app_id should be changed every time a version is updated.

One week after the APP is updated, we will delete the app_id used by the previous version in the background. If the user continues to use the old version to request data, the following error will appear:

  1. {
  2. "err" :{
  3. "code" :-99,
  4. "msg" : "There is a new version, please update in time" ,
  5. "eventId" : "Returned update link"  
  6. }
  7. }

The update notification listener added to the root view will pop up the update page, which greatly improves the update rate of the new version.

  • When this set of processes is used, the mobile terminal hardly needs to control whether to log in. All judgments on whether to log in are thrown to the background to judge. This approach will waste some server resources, but as long as the front and back ends encapsulate a complete set of processes, the development speed will be greatly improved.
  • That's about it for interface encryption. No encryption is unbreakable. All we have to do is to increase the difficulty of cracking. This encryption method will definitely have disadvantages. At this stage, my technology may be too poor, so I can only summarize it like this. Please forgive me if it is not well written.
  • ***I want to say something about taking over other people's code. I recently changed jobs and one of the company's own products needs me to take over the development and iteration. This code has been handled by 5 people from 2015 to now. There is no documentation except the code. Everyone has a different style of writing code. The process of getting familiar with other people's code is painful, but you can also make rapid progress in the process of getting familiar with other people's code. No matter whether other people's code is good or bad, you can always find highlights in everyone's code and find skills that you have not used.

<<:  Great news! Apple iOS App reservation function is now fully available!

>>:  I abandoned my iPhone and switched to Android, but I didn’t miss it at all

Recommend

Unfettered space exploration may be threatening the future of “space security”

【Mobile software: Bo Ke Yuan】As countries and pri...

This may be Apple's first service to enter Android

As one of the largest acquisitions in Apple's...

A must-read for marketers! The underlying logic of hot products

What is a hot product? This is a good question an...

The most popular way of Internet promotion nowadays!

We have sorted out seventeen popular Internet pro...

Why do I often have bruises on my body?

Expert of this article: Fang Jie, Associate Chief...

How did carambola become the "most unpalatable" fruit in the world?

If some fruits win popularity with their taste, t...

Seven rules for Pinduoduo operations

Pinduoduo has improved its operational capabiliti...

How to master offline marketing?

When we do offline marketing , the actual flash s...