Recently, when sorting out the technical points, I found that there are some knowledge points on the computer records, which are some problems encountered in the process of development before, and now I comb them out again

Project requirements: to prevent the data in the WebView from being captured, to add HTTPS verification to the WebView in the APP, and to prevent the attack of HTTPS verification principle, encryption principle, certificate making, etc., have been introduced in many articles, I believe you are familiar with them; This article covers only the parts of implementing HTTPS validation for the Web when multiple server resources are accessed.

First, relevant knowledge points

  1. In general, many companies have turned on the ATS Web Content setting without verifying the certificate, or they have only done one-way certificate verification. In this way, forging a fake valid certificate Web part can easily be caught by others. This time, the Web Content is set to NO. Certificate locking requires the client to store a certificate locally. The working principle is that it will first verify the domain name validity and other information, and then it will verify whether the local certificate is consistent with the server certificate. If consistent, it will shake the link, and if inconsistent, it will disconnect the link. You can prevent man-in-the-middle attacks if the proxy is set up and the data cannot be caught even if a valid certificate that is not on the current company server is configured.
  2. The server configuration parameter clientAuth determines which validation method the above app uses:
parameter describe
clientAuth=false One-way SSL Validation
clientAuth=true Two-way SSL authentication
clientAuth=want Client certificate validation is not mandatory

Second, the implementation process

The following is a regular Web bidirectional HTTPS check

SecTrustResultType result;
SecTrustSetAnchorCertificates(serverTrust, (__bridge CFArrayRef)pinnedCerts);
OSStatus status = SecTrustEvaluate(serverTrust, &result);
 if (status == errSecSuccess &&
    (result == kSecTrustResultProceed ||
    result == kSecTrustResultUnspecified)) {
     NSURLCredential *card = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust];
     completionHandler(NSURLSessionAuthChallengeUseCredential,card);
  } else {
      completionHandler(NSURLSessionAuthChallengeCancelAuthenticationChallenge, nil);
  }
  1. The above is the conventional Web HTTPS two-way verification, but applied to the current project has been verification failure; Normally, when the Web requests data through HTTPS, the server will return all the certificate chain. A domain name and a certificate are one-to-one correspondence and cannot be changed. And a certificate chain will contain several levels of certificates, root certificate – secondary certificate -… . , currently there are 3 levels of certificates in each certificate chain returned by our web request; Finally, after debugging, it was found that a certain H5 page returned Aliyun’s certificate (*.oss.aliyuncs.com) in addition to our company’s own certificate when loading, and the order of certificates returned by each H5 interface may be different, the first certificate chain returned may be our company’s own certificate chain. It may also be the OSS Ali cloud, the order is not necessarily, this is the problem, so the current H5 page verification will fail to open normally.
  2. Change your thinking, Through CFBridgingRelease (SecCertificateCopySubjectSummary (SecTrustGetCertificateAtIndex (challenge. ProtectionSpace. ServerTrust , 0))) take out the server certificate profile, to judge if it is your company currently under the domain name certificate, then check, not like the oss ali cloud not check, direct trust through tested whether their server certificate chain in which order did or can be, according to the normal and test can’t caught:

  1. If, for example, the certificate of oss.aliyun.com is returned above, then adding this whitelist to plist will not have the certificate chain of Aliyun returned, so there is no need to verify. This is also a way of thinking.

Three, the final implementation of the code is as follows

// Get summary information from the certificate chain NSString *summary = CFBridgingRelease(SecCertificateCopySubjectSummary(SecTrustGetCertificateAtIndex(challenge.protectionSpace.serverTrust, 0))); NSLog(@" Current requested certificate summary =%@",summary); / / get trust management object, containing the verification certificate, and custom strategy SecTrustRef serverTrust = challenge. ProtectionSpace. ServerTrust; if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) { if ([summary containsString:@".xxxx.com"]) { NSString *path = [[NSBundle mainBundle] pathForResource:@"xxxx" ofType:@"der"]; NSData *certData = [NSData dataWithContentsOfFile:path]; NSMutableArray *pinnedCerts = [NSMutableArray arrayWithObjects:(__bridge_transfer) id)SecCertificateCreateWithData(NULL, (__bridge CFDataRef)certData), nil]; SecTrustResultType result; SecTrustSetAnchorCertificates(serverTrust, (__bridge CFArrayRef)pinnedCerts); OSStatus status = SecTrustEvaluate(serverTrust, &result); if (status == errSecSuccess && (result == kSecTrustResultProceed || result == kSecTrustResultUnspecified)) { NSURLCredential *card = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust]; completionHandler(NSURLSessionAuthChallengeUseCredential,card); This link completionHandler} else {/ / interrupt (NSURLSessionAuthChallengeCancelAuthenticationChallenge, nil); } }else { NSURLCredential *card = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust]; completionHandler(NSURLSessionAuthChallengeUseCredential,card); } }else { NSURLCredential *card = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust]; completionHandler(NSURLSessionAuthChallengePerformDefaultHandling, card); }

Fourth, expand

1. Test whether to whitelist or not if ATS=NO is set on WEB: ATS=NO (ATS=NO); ATS=NO (ATS=NO); ATS=NO (ATS=NO); (1) The DNS certificate is valid and not expired. (2) The WebView’s verification proxy does not match the local certificate. For example, it can be accessed directly through a domain other than its own company

2. In addition to the Web, the security of pictures was also taken into consideration; Pay a qr code or friends avatar interface, for example, caught in the tools set of other valid certificate can get pictures, check the source know SDWebimage is not check local certificate, so if you want to consider the safety of image need to change the source code, and the methods of the calibration is ok in the webview, the principle is the same.

PS: In addition to the above verification of all the certificate information of the client and server, you can also use the SectrustCopyPublickey (Trust) to take out the public key in the certificate information of each other to achieve the same effect. I won’t go into details here. If you are interested in this, you can try it yourself.