由苹果规定前年一月1日将来,所有APP都使以HTTPS举办网络要,否则不能上架,因此讨论了一晃在iOS中行使HTTPS请求的贯彻。相信我们对HTTPS都要多要少来头了解,这里自己就不再介绍了,紧要力量就是拿传输的报文举行加密,提高安全性。

1、证书准备

证分为两栽,一种植是花钱为认证的机构采购的证件,服务端假诺使用的是立刻看似证的话,那般客户端不需举行什么,用HTTPS举行呼吁虽推行了,苹果内置了这么些吃依赖的干净证书的。另一样栽是温馨创造的注解,使用就好像证的语句是未深受依赖的(当然为非用花钱请),由此用我们以代码上校该证设置为信任关系。

自己就边用的凡xca来制作了根证书,制作流程请参见http://www.2cto.com/Article/201411/347512.html,由于xca不可以导出.jsk的后缀,由此我们要做完根证书后因.p12的格式导出就尽了,之后的证件制作由命执行来完成。自制一个批判处理文件,添加如下命令:

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

将方加粗的ca.p12变动化你导出的.p12文书的名号,123456转移呢公创制证书之密码。

然后以文书夹空白处按停ctrl+shift点击右键,拔取在这里打开命令窗口,在指令窗口中输入“start.bat
ip/域名”来进行批处理文件,其中start.bat是补偿加了上述命令的批判处理文件,ip/域名即你服务器的ip或者域名。执行成功后晤面转一个.jks文件及一个因为你的ip或域名命名的公文夹,文件夹着出一个.cer的阐明,这边的.jks文件将于服务端使用.cer文件将当客户端应用,到此处证书之备选干活便做到了。

2、服务端配置

是因为自弗开服务端好多年,只会以Tomcat,所以立时边仅讲下汤姆cat的布情势,使用其它服务器的同学要自行检索设置方法。

开辟tomcat/conf目录下的server.xml文件将HTTPS的布打开,并展开如下配置:

<Connector URIEncoding=”UTF-8″
protocol=”org.apache.coyote.http11.Http11NioProtocol” port=”8443″
maxThreads=”200″ scheme=”https” secure=”true” SSLEnabled=”true”
sslProtocol=”TLSv1.2″ sslEnabledProtocols=”TLSv1.2″
keystoreFile=”${catalina.base}/ca/ca.jks” keystorePass=”123456″
clientAuth=”false” SSLVerifyClient=”off” netZone=”你的ip或域名”/>

keystoreFile是你.jks文件放置的目,keystorePass是您造证书时设置的密码,netZone填写您的ip或域名。瞩目苹果要求协议假使TLSv1.2以上

3、iOS端配置

先是将前面生成的.cer文件添加到项目受到,注意在加上之时光择要长的targets。

1.下NSURLSession举办呼吁

代码如下:

NSString *urlString =
@”https://xxxxxxx“;
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];

得实现NSURLSessionDataDelegate中之URLSession:didReceiveChallenge:completionHandler:方法来开展证件的校验,代码如下:

– (void)URLSession:(NSURLSession *)session
didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge
 completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition
disposition, NSURLCredential * _Nullable
credential))completionHandler {
    NSLog(@”证书认证”);
    if ([[[challenge protectionSpace] authenticationMethod]
isEqualToString: NSURLAuthenticationMethodServerTrust]) {
        do
        {
            SecTrustRef serverTrust = [[challenge protectionSpace]
serverTrust];
            NSCAssert(serverTrust != nil, @”serverTrust is nil”);
            if(nil == serverTrust)
                break; /* failed */
            /**
             *  导入多张CA证书(Certification
Authority,帮忙SSL证书以及由签定的CA),请替换掉你的证件名称
             */
            NSString *cerPath = [[NSBundle mainBundle]
pathForResource:@”ca” ofType:@”cer”];//自签约证书
            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];
}

那会儿即可成功请求到服务端。

流动:调用SecTrustSetAnchorCertificates设置可信任关序列表后即使单纯会当设置的列表中举行认证,会屏蔽掉系统本来的深信列表,要如系统的累由效用而调用SecTrustSetAnchorCertificates方法,第二独参数设置成NO即可。

2.用AFNetworking举行呼吁

AFNetworking首先需要配备AFSecurityPolicy类,AFSecurityPolicy类封装了表明校验的进程。

/**
 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;
    }];

上述代码通过被AFHTTPSessionManager重新设置证书验证回调来协调作证证书,然后用好之评释出席到不过信任的证件列表中,即可通过关系之校验。

由于服务端使用.jks是一个证书库,客户端取到的证件或连一照,我立边获取到了少本,具体获取到骨干但是通过SecTrustGetCertificateCount方法赢得证书个数,AFNetworking在evaluateServerTrust:forDomain:方法中,AFSSLPinningMode的色为AFSSLPinningModeCertificate和AFSSLPinningModePublicKey的时光都发生校验服务端的证书个数和客户端信任的表明数量是否同样,假设无一样的言辞无法请成功,所以这边我即使修改外的源码,当有一个校验成功时即算成功。

当型也AFSSLPinningModeCertificate时

return trustedCertificateCount == [serverCertificates count] – 1;

为AFSSLPinningModePublicKey时

return trustedPublicKeyCount > 0 &&
((self.validatesCertificateChain) || (!self.validatesCertificateChain
&& trustedPublicKeyCount >= 1));

错开丢了次块被之trustedPublicKeyCount == [serverCertificates
count]的条件。

旋即边用的AFNetworking的版也2.5.3,假诺其它版本有不同之处请自行遵照实际情状修改。

demo地址:https://github.com/fengling2300/networkTest

相关文章

网站地图xml地图