HTTPS for network requests

Since Apple stipulates that after January 1, 2017, all APPs must use HTTPS for network requests, otherwise they cannot be put on the shelves, so I studied the implementation of using HTTPS requests in iOS. I believe everyone knows more or less about HTTPS, so I won't introduce it here. The main function is to encrypt transmitted messages to improve security.
1. Certificate preparation

There are two types of certificates. One is a certificate purchased from a certification authority. If the server uses this type of certificate, the general client does not need to do anything, just use HTTPS to make the request. Apple has built-in those Of the trusted root certificate. The other is a self-made certificate. If you use this type of certificate, it is not trusted (of course you don't need to spend money to buy it), so we need to set the certificate as a trusted certificate in the code.

I used xca to make the root certificate, please refer to the making process

http://www.2cto.com/Article/201411/347512.html

, Because xca cannot export the .jsk suffix, we only need to export the root certificate in .p12 format after making the root certificate, and the subsequent certificate making is done by the command line. Make a batch file by yourself and add the following commands:

  set ip=%1%
    md %ip%
    keytool -importkeystore -srckeystore 
    ca.p12
     -srcstoretype PKCS12 -srcstorepass 
    123456
     -destkeystore ca.jks -deststoretype JKS -deststorepass 
    123456
    keytool -genkeypair -alias server-%ip% -keyalg RSA -keystore ca.jks -storepass 
    123456
     -keypass 
    123456
     -validity 3650 -dname "CN=%ip%, OU=ly, O=hik, L=hz, ST=zj, C=cn"
    keytool -certreq -alias server-%ip% -storepass 
    123456
     -file %ip%\server-%ip%.certreq -keystore ca.jks
    keytool -gencert -alias ca -storepass 
    123456
     -infile %ip%\server-%ip%.certreq -outfile %ip%\server-%ip%.cer -validity 3650 -keystore ca.jks  
    keytool -importcert -trustcacerts -storepass 
    123456
     -alias server-%ip% -file %ip%\server-%ip%.cer -keystore ca.jks
    keytool -delete -keystore ca.jks -alias ca -storepass 
    123456

Change the bolded ca.p12 above to the name of the .p12 file you exported, and change 123456 to the password you created the certificate.

Then hold down ctrl+shift and right-click in the blank space of the folder, choose to open the command window here, and enter "start.bat ip/domain name" in the command window to execute the batch file, where start.bat is the above command added The ip/domain name is the ip or domain name of your server. After the execution is successful, a .jks file and a folder named after your ip or domain name will be generated. There is a .cer certificate in the folder. The .jks file here will be used on the server side. The cer file will be on the client side. Use, the preparation work for the certificate is completed here.
2. Server configuration

Since I have not been a server for many years and only use Tomcat, I will only talk about the configuration method of Tomcat here. Students who use other servers please find the setting method by themselves.

Open the server.xml file in the tomcat/conf directory to open the HTTPS configuration, and configure the following:

keystoreFile is the directory where your .jks file is placed, keystorePass is the password you set when you make the certificate, and netZone fills in your ip or domain name. Note that Apple requires the protocol to be TLSv1.2 or higher.
3. iOS configuration

First add the previously generated .cer file to the project, and pay attention to the targets to be added when adding.

1. Use NSURLSession to request

  • (void)sessionBtnClicked {
    NSString *urlString = @”https://10.20.129.25:8443/dreamVideo/restful/show“;
    NSURL *url = [NSURL URLWithString:urlString];
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:10.0f];
    NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:[NSOperationQueue mainQueue]];
    NSURLSessionDataTask *task = [session dataTaskWithRequest:request];
    [task resume];
    }

  • (void)URLSession:(NSURLSession )session dataTask:(NSURLSessionDataTask )dataTask
    didReceiveResponse:(NSURLResponse *)response
    completionHandler:(void (^)(NSURLSessionResponseDisposition disposition))completionHandler {
    NSLog(@"Server response received");
    //Note : Here you need to use the completionHandler callback to tell the system how to handle the data returned by the server
    //The default is to cancel
    /**
    NSURLSessionResponseCancel = 0, the default processing method, cancel
    NSURLSessionResponseAllow = 1, receive the data returned by the server
    NSURLSessionResponseBecomeDownload = 2, become a download Request
    NSURLSessionResponseBecomeStream to become a stream
    */
    completionHandler(NSURLSessionResponseAllow);
    }

  • (void)URLSession:(NSURLSession )session dataTask:(NSURLSessionDataTask )dataTask
    didReceiveData:(NSData *)data {
    NSLog(@”Get service segment data”);
    NSLog(@”%@”,[self jsonToDictionary:data]) ;
    }

  • (void)URLSession:(NSURLSession )session task:(NSURLSessionTask )task
    didCompleteWithError:(nullable NSError *)error {
    NSLog(@”请求完成”);
    }

  • (void)URLSession:(NSURLSession )session didReceiveChallenge:(NSURLAuthenticationChallenge )challenge
    completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential * _Nullable credential))completionHandler {
    NSLog(@"certificate certification");
    if ( Space [[[challenge protection ] authenticationMethod] isEqualToString: NSURLAuthenticationMethodServerTrust]) {
    do
    {
    SecTrustRef serverTrust = [[challenge protectionSpace] serverTrust];
    NSCAssert(serverTrust != nil, @”serverTrust is nil”);
    if(nil == serverTrust)
    break; /* failed * //
    **
    * Import multiple CA certificates (Certification Authority, support SSL certificate and self-signed CA), please replace your certificate name
    */
    NSString *cerPath = [[NSBundle mainBundle] pathForResource:@”ca” ofType:@”cer”];//Self-signed certificate
    NSData* caCert = [NSData dataWithContentsOfFile:cerPath];

        NSCAssert(caCert != nil, @"caCert is nil");
        if(nil == caCert)
            break; /* failed */
    
        SecCertificateRef caRef = SecCertificateCreateWithData(NULL, (__bridge CFDataRef)caCert);
        NSCAssert(caRef != nil, @"caRef is nil");
        if(nil == caRef)
            break; /* failed */
    
        //可以添加多张证书
        NSArray *caArray = @[(__bridge id)(caRef)];
    
        NSCAssert(caArray != nil, @"caArray is nil");
        if(nil == caArray)
            break; /* failed */
    
        //将读取的证书设置为服务端帧数的根证书
        OSStatus status = SecTrustSetAnchorCertificates(serverTrust, (__bridge CFArrayRef)caArray);
        NSCAssert(errSecSuccess == status, @"SecTrustSetAnchorCertificates failed");
        if(!(errSecSuccess == status))
            break; /* failed */
    
        SecTrustResultType result = -1;
        //通过本地导入的证书来验证服务器的证书是否可信
        status = SecTrustEvaluate(serverTrust, &result);
        if(!(errSecSuccess == status))
            break; /* failed */
        NSLog(@"stutas:%d",(int)status);
        NSLog(@"Result: %d", result);
    
        BOOL allowConnect = (result == kSecTrustResultUnspecified) || (result == kSecTrustResultProceed);
        if (allowConnect) {
            NSLog(@"success");
        }else {
            NSLog(@"error");
        }
    
        /* kSecTrustResultUnspecified and kSecTrustResultProceed are success */
        if(! allowConnect)
        {
            break; /* failed */
        }
    

if 0

        /* Treat kSecTrustResultConfirm and kSecTrustResultRecoverableTrustFailure as success */
        /*   since the user will likely tap-through to see the dancing bunnies */
        if(result == kSecTrustResultDeny || result == kSecTrustResultFatalTrustFailure || result == kSecTrustResultOtherError)
            break; /* failed to trust cert (good in this case) */

endif

        // The only good exit point
        NSLog(@"信任该证书");

        NSURLCredential *credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust];
        completionHandler(NSURLSessionAuthChallengeUseCredential,credential);
        return [[challenge sender] useCredential: credential
                      forAuthenticationChallenge: challenge];

    }
    while(0);
}

// Bad dog
NSURLCredential *credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust];
completionHandler(NSURLSessionAuthChallengeCancelAuthenticationChallenge,credential);
return [[challenge sender] cancelAuthenticationChallenge: challenge];

}

  • (NSDictionary )jsonToDictionary:(NSData )jsonData {
    NSError *jsonError;
    NSDictionary *resultDic = [NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONReadingMutableLeaves error:&jsonError];
    return resultDic;
    } to successfully request to the server. After setting the trusted certificate list with SecTrustSetAnchorCertificates, it will only be verified in the set list, which will shield the original trust list of the system. To make the system continue to work, just call the SecTrustSetAnchorCertificates method and set the second parameter to NO.

2. Use AFNetworking to make a request

AFNetworking first needs to configure the AFSecurityPolicy class. The AFSecurityPolicy class encapsulates the certificate verification process.

/**
 AFSecurityPolicy分三种验证模式:
 AFSSLPinningModeNone:只是验证证书是否在信任列表中
 AFSSLPinningModeCertificate:该模式会验证证书是否在信任列表中,然后再对比服务端证书和客户端证书是否一致
 AFSSLPinningModePublicKey:只验证服务端证书与客户端证书的公钥是否一致
*/

AFSecurityPolicy *securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeCertificate];
    securityPolicy.allowInvalidCertificates = YES;//是否允许使用自签名证书
    securityPolicy.validatesDomainName = NO;//是否需要验证域名,默认YES

    AFHTTPSessionManager *_manager = [AFHTTPSessionManager manager];
    _manager.responseSerializer = [AFHTTPResponseSerializer serializer];
    _manager.securityPolicy = securityPolicy;
    //设置超时
    [_manager.requestSerializer willChangeValueForKey:@"timeoutinterval"];
    _manager.requestSerializer.timeoutInterval = 20.f;
    [_manager.requestSerializer didChangeValueForKey:@"timeoutinterval"];
    _manager.requestSerializer.cachePolicy = NSURLRequestReloadIgnoringCacheData;
    _manager.responseSerializer.acceptableContentTypes  = [NSSet setWithObjects:@"application/xml",@"text/xml",@"text/plain",@"application/json",nil];

    __weak typeof(self) weakSelf = self;
    [_manager setSessionDidReceiveAuthenticationChallengeBlock:^NSURLSessionAuthChallengeDisposition(NSURLSession *session, NSURLAuthenticationChallenge *challenge, NSURLCredential *__autoreleasing *_credential) {

        SecTrustRef serverTrust = [[challenge protectionSpace] serverTrust];
        /**
         *  导入多张CA证书
         */
        NSString *cerPath = [[NSBundle mainBundle] pathForResource:@"ca" ofType:@"cer"];//自签名证书
        NSData* caCert = [NSData dataWithContentsOfFile:cerPath];
        NSArray *cerArray = @[caCert];
        weakSelf.manager.securityPolicy.pinnedCertificates = cerArray;

        SecCertificateRef caRef = SecCertificateCreateWithData(NULL, (__bridge CFDataRef)caCert);
        NSCAssert(caRef != nil, @"caRef is nil");

        NSArray *caArray = @[(__bridge id)(caRef)];
        NSCAssert(caArray != nil, @"caArray is nil");

        OSStatus status = SecTrustSetAnchorCertificates(serverTrust, (__bridge CFArrayRef)caArray);
        SecTrustSetAnchorCertificatesOnly(serverTrust,NO);
        NSCAssert(errSecSuccess == status, @"SecTrustSetAnchorCertificates failed");

        NSURLSessionAuthChallengeDisposition disposition = NSURLSessionAuthChallengePerformDefaultHandling;
        __autoreleasing NSURLCredential *credential = nil;
        if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) {
            if ([weakSelf.manager.securityPolicy evaluateServerTrust:challenge.protectionSpace.serverTrust forDomain:challenge.protectionSpace.host]) {
                credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust];
                if (credential) {
                    disposition = NSURLSessionAuthChallengeUseCredential;
                } else {
                    disposition = NSURLSessionAuthChallengePerformDefaultHandling;
                }
            } else {
                disposition = NSURLSessionAuthChallengeCancelAuthenticationChallenge;
            }
        } else {
            disposition = NSURLSessionAuthChallengePerformDefaultHandling;
        }

        return disposition;
    }];

AFN package

/ * How to call when in use /

NSString *urlString = @"https://10.20.129.25:8443/dreamVideo/restful/show";
HttpManager *httpManager = [HttpManager shareHttpManager];
[httpManager post:urlString withParameters:nil success:^(NSURLSessionDataTask *task, id responseObject) {
    NSLog(@"success");
} failure:^(NSURLSessionDataTask *task, NSError *error) {
    NSLog(@"failure");
}];

import “HttpManager.h”

@interface HttpManager : NSObject
@property(nonatomic,copy)NSString *etag;
+(instancetype)shareHttpManager;
//https访问

-(void)post:(NSString )url withParameters:(id)parameters success:(void (^)(NSURLSessionDataTask _Nonnull task, id _Nullable responseObject))success failure:(void (^)(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error))failure;

import “HttpManager.h”

#import "HttpManager.h"
#import "AFHTTPSessionManager.h"

@interface HttpManager()

@property(nonatomic,retain)AFHTTPSessionManager *manager;

@end

@implementation HttpManager

+(instancetype)shareHttpManager{
    static dispatch_once_t onece = 0;
    static HttpManager *httpManager = nil;
    dispatch_once(&onece, ^(void){
        httpManager = [[self alloc]init];
    });
    return httpManager;
}

//https访问
-(void)post:(NSString *)url withParameters:(id)parameters success:(void (^)(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject))success failure:(void (^)(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error))failure {
    AFSecurityPolicy *securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeCertificate];

//    securityPolicy = [AFSecurityPolicy defaultPolicy];
    securityPolicy.allowInvalidCertificates = YES;
    securityPolicy.validatesDomainName = NO;

    _manager = [AFHTTPSessionManager manager];
    _manager.responseSerializer = [AFHTTPResponseSerializer serializer];
    _manager.securityPolicy = securityPolicy;
    //设置超时时间
    [_manager.requestSerializer willChangeValueForKey:@"timeoutinterval"];
    _manager.requestSerializer.timeoutInterval = 20.f;
    [_manager.requestSerializer didChangeValueForKey:@"timeoutinterval"];
    _manager.requestSerializer.cachePolicy = NSURLRequestReloadIgnoringCacheData;
//    if (_etag) {
    
    
//        [_manager.requestSerializer setValue:_etag forHTTPHeaderField:@"If-None-Match"];
//    } else {
    
    
//        [_manager.requestSerializer setValue:@"bb" forHTTPHeaderField:@"If-None-Match"];
//    }
    _manager.responseSerializer.acceptableContentTypes  = [NSSet setWithObjects:@"application/xml",@"text/xml",@"text/plain",@"application/json",nil];

    __weak typeof(self) weakSelf = self;
    [_manager setSessionDidReceiveAuthenticationChallengeBlock:^NSURLSessionAuthChallengeDisposition(NSURLSession *session, NSURLAuthenticationChallenge *challenge, NSURLCredential *__autoreleasing *_credential) {

        SecTrustRef serverTrust = [[challenge protectionSpace] serverTrust];
        /**
         *  导入多张CA证书(Certification Authority,支持SSL证书以及自签名的CA),请替换掉你的证书名称
         */
        NSString *cerPath = [[NSBundle mainBundle] pathForResource:@"ca" ofType:@"cer"];//自签名证书
        NSData* caCert = [NSData dataWithContentsOfFile:cerPath];
        NSArray *cerArray = @[caCert];
        weakSelf.manager.securityPolicy.pinnedCertificates = cerArray;

        SecCertificateRef caRef = SecCertificateCreateWithData(NULL, (__bridge CFDataRef)caCert);
        NSCAssert(caRef != nil, @"caRef is nil");

        NSArray *caArray = @[(__bridge id)(caRef)];
        NSCAssert(caArray != nil, @"caArray is nil");

        OSStatus status = SecTrustSetAnchorCertificates(serverTrust, (__bridge CFArrayRef)caArray);
        SecTrustSetAnchorCertificatesOnly(serverTrust,NO);
        NSCAssert(errSecSuccess == status, @"SecTrustSetAnchorCertificates failed");

        NSURLSessionAuthChallengeDisposition disposition = NSURLSessionAuthChallengePerformDefaultHandling;
        __autoreleasing NSURLCredential *credential = nil;
        if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) {
            if ([weakSelf.manager.securityPolicy evaluateServerTrust:challenge.protectionSpace.serverTrust forDomain:challenge.protectionSpace.host]) {
                credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust];
                if (credential) {
                    disposition = NSURLSessionAuthChallengeUseCredential;
                } else {
                    disposition = NSURLSessionAuthChallengePerformDefaultHandling;
                }
            } else {
                disposition = NSURLSessionAuthChallengeCancelAuthenticationChallenge;
            }
        } else {
            disposition = NSURLSessionAuthChallengePerformDefaultHandling;
        }

        return disposition;
    }];


    [_manager POST:url parameters:parameters success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
        NSHTTPURLResponse *response = (NSHTTPURLResponse *)task.response;
        NSDictionary *headDic = response.allHeaderFields;
        NSInteger code = response.statusCode;
        NSLog(@"response statusCode is %zd",code);
//        NSString *etag = headDic[@"Etag"];
//        if (etag) {
    
    
//            _etag = etag;
//        }
        NSLog(@"%@",[[NSString alloc]initWithData:responseObject encoding:NSUTF8StringEncoding]);
        NSDictionary *responseDic = [self jsonToDictionary:[[NSString alloc]initWithData:responseObject encoding:NSUTF8StringEncoding]];
        success(task,responseObject);
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        NSHTTPURLResponse *response = (NSHTTPURLResponse *)task.response;
        NSDictionary *headDic = response.allHeaderFields;
        NSInteger code = response.statusCode;
        NSLog(@"response statusCode is %zd",code);
        failure(task,error);
    }];
}

- (NSDictionary *)jsonToDictionary:(NSString *)jsonString {
    NSData *jsonData = [jsonString dataUsingEncoding:NSUTF8StringEncoding];
    NSError *jsonError;
    NSDictionary *resultDic = [NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONReadingMutableLeaves error:&jsonError];
    return resultDic;
}

@end

Guess you like

Origin blog.csdn.net/woruosuifenglang/article/details/53930154