关于ios项目绕过证书访问https

听说苹果发布了声明,将于年底将所有iOS应用的http访问强制改为https访问。个人认为这是个好事,启用HTTPS网络连接之后,数据传输的安全性将大幅提示,不容易被黑客拦截破译。
所以得跟上形势不是,这也许就是程序员的无奈,相当一个不过是的好程序员就得不断的学习新的知识。下面就是我用NSURLSession封装好的数据请求类。

  • 说明:请求方法结合了MD5加密,大家看代码的时候注意看NSURLSessionTaskDelegate代理方法即可

AsyncNetWorkRequest.h 中

#import <Foundation/Foundation.h>

@interface AsyncNetWorkRequest : NSObject

// 定义block块属性
// 网络请求成功
@property (nonatomic, copy) void(^successBlock)(NSData *data);

// 网络请求失败
@property (nonatomic, copy) void(^errorBlock)(NSError *error);

+ (instancetype)startRequestDataWithURLStr:(NSString *)str parameter:(NSDictionary *)parameter requestType:(NSString *)type SucessBlock:(void (^)(NSData *data))sucessBlock ErrorBlock:(void (^)(NSError *error))errorBlock;
+ 
@end

AsyncNetWorkRequest.m 中


#import "AsyncNetWorkRequest.h"
#import "MD5Encryption.h"

@interface AsyncNetWorkRequest () <NSURLSessionTaskDelegate>

@end



@implementation AsyncNetWorkRequest

- (instancetype)init {
    self = [super init];
    if (self) {

    }
    return self;
}

// 对外数据请求类
+ (instancetype)startRequestDataWithURLStr:(NSString *)str parameter:(NSDictionary *)parameter requestType:(NSString *)type SucessBlock:(void (^)(NSData *data))sucessBlock ErrorBlock:(void (^)(NSError *error))errorBlock
{
    AsyncNetWorkRequest *async = [[AsyncNetWorkRequest alloc] init];

    async.successBlock = sucessBlock;
    async.errorBlock = errorBlock;

    // 获取加密后的数据请求字符串
    NSString *urlString = [MD5Encryption startMD5EncryptionWithParameters:parameter URLString:str];
    NSLog(@"打印数据请求字符串 %@", urlString);
    NSURL *url = [NSURL URLWithString:urlString];
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];

    //  get请求
    if ([type isEqualToString:@"GET"]) {
        [async requestGETWithRequest:request Async:async];
    }
    // post请求
    else {
        // 用 ?分割 取出要上传的数据。
        NSArray *array = [urlString componentsSeparatedByString:@"?"];
        NSString *stringBody = array[1];
        // 将上传数据转化为data
        NSData *bodyData = [stringBody dataUsingEncoding:NSUTF8StringEncoding];
        NSURL *urlPost = [NSURL URLWithString:str];
        NSMutableURLRequest *requestPost = [NSMutableURLRequest requestWithURL:urlPost];
        [async requestPOSTWithRequest:requestPost Async:async BodyData:bodyData];
    }
    return async;
}


#pragma mark - post请求
- (void)requestPOSTWithRequest:(NSMutableURLRequest *)request Async:(AsyncNetWorkRequest *)async BodyData:(NSData *)bodyData
{
    request.HTTPMethod = @"POST";
    request.HTTPBody = bodyData;


    NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
    NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration];

    NSURLSessionDataTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {

        if (error == nil) {
            NSLog(@"POST请求成功");
            async.successBlock(data);

        }
        else {
            NSLog(@"POST请求失败");
            async.errorBlock(error);
        }
    }];
    [task resume];

}

#pragma mark - get请求
- (void)requestGETWithRequest:(NSMutableURLRequest *)request Async:(AsyncNetWorkRequest *)async
{
    request.HTTPMethod = @"GET";
    // 创建会话
    NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
    configuration.TLSMaximumSupportedProtocol = kTLSProtocol1;

    NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration delegate:self delegateQueue:[NSOperationQueue mainQueue]];

    NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {

        if (error == nil) {
            NSLog(@"GET数据请求成功");
            async.successBlock(data);
        }

        else {
            NSLog(@"GET数据请求失败 %@", [error description]);
            async.errorBlock(error);
        }
    }];
    [dataTask resume];

}


#if 1 - 这是第一种写法
// ios项目绕过证书访问https程序,当你向服务器请求时,服务器需要证书时会走下面的方法
- (void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential))completionHandler
{

    // 处理认证证书的方案
    NSString *method = challenge.protectionSpace.authenticationMethod;
    NSLog(@"%@", method);

    if([method isEqualToString:NSURLAuthenticationMethodServerTrust]){

        NSString *host = challenge.protectionSpace.host;
        NSLog(@" 分割 %@", host);

        NSURLCredential *credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust];

        completionHandler(NSURLSessionAuthChallengeUseCredential, credential);
        return;
    }

    NSString *thePath = [[NSBundle mainBundle] pathForResource:@"client" ofType:@"p12"];
    NSData *PKCS12Data = [[NSData alloc] initWithContentsOfFile:thePath];
    CFDataRef inPKCS12Data = (CFDataRef)CFBridgingRetain(PKCS12Data);
    SecIdentityRef identity;

    // 读取p12证书中的内容
    OSStatus result = [self extractP12Data:inPKCS12Data toIdentity:&identity];
    if(result != errSecSuccess){

        completionHandler(NSURLSessionAuthChallengeCancelAuthenticationChallenge, nil);
        return;
    }

    SecCertificateRef certificate = NULL;
    SecIdentityCopyCertificate (identity, &certificate);

    const void *certs[] = {certificate};
    CFArrayRef certArray = CFArrayCreate(kCFAllocatorDefault, certs, 1, NULL);

    NSURLCredential *credential = [NSURLCredential credentialWithIdentity:identity certificates:(NSArray*)CFBridgingRelease(certArray) persistence:NSURLCredentialPersistencePermanent];

    completionHandler(NSURLSessionAuthChallengeUseCredential, credential);
}


-(OSStatus) extractP12Data:(CFDataRef)inP12Data toIdentity:(SecIdentityRef*)identity {

    OSStatus securityError = errSecSuccess;

    CFStringRef password = CFSTR("the_password");
    const void *keys[] = { kSecImportExportPassphrase };
    const void *values[] = { password };

    CFDictionaryRef options = CFDictionaryCreate(NULL, keys, values, 1, NULL, NULL);

    CFArrayRef items = CFArrayCreate(NULL, 0, 0, NULL);
    securityError = SecPKCS12Import(inP12Data, options, &items);

    if (securityError == 0) {
        CFDictionaryRef ident = CFArrayGetValueAtIndex(items,0);
        const void *tempIdentity = NULL;
        tempIdentity = CFDictionaryGetValue(ident, kSecImportItemIdentity);
        *identity = (SecIdentityRef)tempIdentity;
    }

    if (options) {
        CFRelease(options);
    }

    return securityError;
}

#endif

#if 0 - 这是第二种写法
#pragma mark - ios项目绕过证书访问https程序,当向服务端请求数据时,会通过该方法进行证书验证
- (void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential * _Nullable))completionHandler
{

    if (challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust) {

        NSLog(@"服务端证书认证");

        SecTrustRef servertrust = challenge.protectionSpace.serverTrust;
        SecCertificateRef certi= SecTrustGetCertificateAtIndex(servertrust, 0);
        NSData *certidata = CFBridgingRelease(CFBridgingRetain(CFBridgingRelease(SecCertificateCopyData(certi))));
        NSString *path = [[NSBundle mainBundle] pathForResource:@"tomcat_server" ofType:@"cer"];
        NSData *localCertiData = [NSData dataWithContentsOfFile:path];

        if ([certidata isEqualToData:localCertiData]) {

           NSURLCredential *credential = [[NSURLCredential alloc] initWithTrust:servertrust];

            [challenge.sender useCredential:credential forAuthenticationChallenge:challenge];
            completionHandler(NSURLSessionAuthChallengeUseCredential, credential);

        }

        else {
            completionHandler(NSURLSessionAuthChallengeCancelAuthenticationChallenge, nil);
            NSLog(@"服务端认证失败");
        }
    }

}

#endif

@end

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值