iOS参数签名:请求参数按照ASCII码从小到大排序、拼接、加密(递归的方式实现)案例:条码支付综合前置平台申请退款【修订版】

2021-04-15 16:09:09 浏览数 (1)

前言

支付类app为了安全起见,除了使用【防代理分析请求数据】,还可采用签名的方式进一步进行限制防止请求和返回报文被修改。

iOS请求安全防护【1、 防代理分析请求数据 2、SSL证书认证3、采用签名禁止修改报文4、不在本地缓存网络请求报文5、利用NSURLProtocol 拦截请求修改HTTPHeaderField】 1、iOS网络请求安全优化:2、不走全局proxy的方案;3、允许不验证SSL证书;4、拦截请求;5、DoH &DoT 1、iOS安全【 SSL证书验证, 让Charles再也无法抓你的请求数据】2、iOS逆向:【绕过证书校验】 文章地址: https://blog.csdn.net/z929118967/article/details/102511852

  • 应用场景:防止请求参数被恶意修改

在对接第三方支付的时候,第三方会要求参数按照ASCII码从小到大排序。 1、银联的退款接口签名:https://kunnan.blog.csdn.net/article/details/115084885 ◆ key:签名时用机构对应的密钥key ◆签名算法:MD5,后续会兼容SHA1、SHA256、HMAC等 2、微信支付接口签名:https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=4_3 ◆ key设置路径:微信商户平台(pay.weixin.qq.com)-->账户设置-->API安全-->密钥设置 ◆注:HMAC-SHA256签名方式,部分语言的hmac方法生成结果二进制结果,需要调对应函数转化为十六进制字符串 ◆生成随机数算法:调用随机数函数生成,将得到的值转换为字符串。 ◆使用openssl命令来自己导出pem证书(p12 to pem):openssl pkcs12 -clcerts -nokeys -in apiclient_cert.p12 -out apiclient_cert.pem ◆ 微信支付接口签名校验工具 :https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=20_1

  • 原文

https://blog.csdn.net/z929118967/article/details/108195721

从CSDN下载demo地址:https://download.csdn.net/download/u011018979/15483107

1、demo 数组用[]表示,对象(字典)用{} 表示进行排序拼接。 2、数组排序可选,数组内部,只对字符串元素进行排序,并不与字典key参与排序。 (字典和数组独立排序)

  • 参数
代码语言:javascript复制
    NSDictionary *params = @{@"sid" :  @"iOS逆向",
                             @"certificateInfoList" :  @"https://kunnan.blog.csdn.net/article/details/108195721" ,
                             @"storePicsList" : @"https://kunnan.blog.csdn.net" ,
                             };

  • 效果
代码语言:javascript复制

2021-02-26 15:43:42.208991 0800 SignatureGenerator[16231:1928569] 按照参数名ASCII码从小到大排序:《certificateInfoList=https://kunnan.blog.csdn.net/article/details/108195721&sid=iOS逆向&storePicsList=https://kunnan.blog.csdn.net》


2021-02-26 15:43:42.209280 0800 SignatureGenerator[16231:1928569] sign:195b9caecc41681ebd1b74261f858052

I、实现步骤

为了保证数据传输过程中的数据真实性和完整性,我们需要对数据进行数字签名,在接收签名数据之后进行签名校验。

数字签名有两个步骤:

1、先按一定规则拼接要签名的原始串, 2、再选择具体的算法和密钥计算出签名结果(注意:签名时将字符串转化成字节流时指定的编码字符集应与参数charset一致。)

  • 签名原始串

所有参数按照字段名的ascii码从小到大排序后使用QueryString(URL键值对)的格式(即key1=value1&key2=value2…)拼接而成,空值不传递,不参与签名组串。

代码语言:javascript复制
<xml>
<body><![CDATA[测试支付]]></body>
<mch_create_ip><![CDATA[127.0.0.1]]></mch_create_ip>
<mch_id><![CDATA[7551000001]]></mch_id>
<nonce_str><![CDATA[1409196838]]></nonce_str>
<out_trade_no><![CDATA[141903606228]]></out_trade_no>
<service><![CDATA[unified.trade.micropay]]></service>
<sign><![CDATA[52836FAD27E0813DAA4072A4BDA9F654]]></sign>
<total_fee><![CDATA[1]]></total_fee>
</xml>
代码语言:javascript复制
body=测试支付&mch_create_ip=127.0.0.1&mch_id=7551000001&nonce_str=1409196838&out_trade_no=
141903606228&service=unified.trade.micropay&total_fee=1

1.1 签名原始串:按照参数名ASCII码从小到大排序并拼接[递归的方式进行实现]

设所有发送或者接收到的数据为集合M,将集合M内的参数和参数值按照参数名ASCII码从小到大排序(字典序),使用QueryString的格式(即key1=value1&key2=value2…)拼接成字符串stringA。

1、demo 数组用[]表示,对象(字典)用{} 表示进行排序拼接。 2、数组排序可选,数组内部,只对字符串元素进行排序,并不与字典key参与排序。 字典和数组独立排序

代码语言:javascript复制
isPreAuth=false&isWipeZero=true&needTrade=falsetotalAmount=22

  • 处理key对应的Value是字典的情况
代码语言:javascript复制
/**
 
 递归
 
 - 处理key对应的Value是字典的情况

     request body参数名ASCII码从小到大排序(字典序),
 使用URL键值对的格式拼接成字符串    (key1=value1&key2=value2…)

 */
  (NSString *)sortedDictionary:(NSMutableDictionary *)originParam {
    
    NSDictionary *dict = originParam;
    

    NSMutableString *contentString =[NSMutableString string];

    NSArray *keys = [dict allKeys];
    

    //按字母顺序排序

    NSArray *sortedArray = [keys sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2) {

        return [obj1 compare:obj2 options:NSNumericSearch];

    }];

    //拼接字符串

    for (NSString *categoryId in sortedArray) {

#pragma mark - ******** todo value区分数组[,]、字符串、字段对象{}
        

        id  categoryIdV = [dict objectForKey:categoryId];
        
        
//
        if( [categoryIdV isKindOfClass:NSString.class]){
            

        
        }
        else         if( [categoryIdV isKindOfClass:NSDictionary.class]){
            
            
            categoryIdV = [self sortedDictionary:categoryIdV];
            
            categoryIdV = [NSString stringWithFormat:@"%@%@%@",@"{",categoryIdV,@"}"];
            
            
            
        }
        // 数组就[]
        
        else         if( [categoryIdV isKindOfClass:NSArray.class]){
            

            
            categoryIdV =   [self sortedDictionaryArr:categoryIdV];
            
            
            
        }

        
        
        if ([contentString length] <= 0) {
            //第一个参数
        }else{
            [contentString appendString:@"&"];
        }
        
        
        [contentString appendFormat:@"%@=%@", categoryId,categoryIdV ];
        
        


    }

    
    NSLog(@"%@",contentString);
    return contentString;
}

  • 处理key对应的Value是数组的情况

签名数组ASCII码排序的地方相关问题解答:https://kunnan.blog.csdn.net/article/details/115355062 新增集合元素排序【可选】:对于数组排序,先按照数组元素的class类型进行分组,其中的子数组是字符串类型的话,就对其进行排序之后再重新组合到新的数组中。然后再进行遍历递归拼接

0 人点赞