Build a secure app! iOS security series: HTTPS

Build a secure app! iOS security series: HTTPS

[[144627]]

How to create a secure App? This is a question that every mobile developer must face. In the field of mobile App development, development engineers generally lack consideration for security. Due to the closed nature of the iOS platform, the security issues encountered are much less than those of Android. This has led to many iOS developers not having much in-depth knowledge of security. However, for a qualified software developer, security knowledge is one of the essential knowledge.

For iOS devices that have not been jailbroken, due to the powerful sandbox and authorization mechanism, as well as the App Store controlled by Apple itself, the invasion of malicious software is basically eliminated. But in addition to system security, we still face many security issues: network security, data security, etc. Each of them involves a very wide range of issues. Security is a very large topic. I am not a professional security expert. I just analyze the various security issues we often encounter from the perspective of developers, and propose common solutions to communicate with you.

Every software engineer has an obligation to protect the privacy and security of user data.

First of all, network security. Each layer of the OSI model will face corresponding network security issues, which involve a wide range of issues. Network security is also the most prosperous field in the security field. In this article, we only explain the core concepts of HTTPS and its implementation on the iOS platform in a simple way from the perspective of mobile application development. It is recommended that all applications that are still using HTTP be upgraded to HTTPS.

Introduction: The era of HTTPS for all Internet sites has arrived

1. HTTPS

In fact, from the perspective of final data parsing, HTTPS is no different from HTTP. HTTPS puts the HTTP protocol data packet into the SSL/TSL layer for encryption, and then forms an IP datagram for transmission at the TCP/IP layer to ensure the security of the transmitted data. For the receiving end, after SSL/TSL decrypts the received data packet, it passes the data to the HTTP protocol layer, which is ordinary HTTP data. Both HTTP and SSL/TSL are in the application layer of the OSI model. Switching from HTTP to HTTPS is a very simple process. Before doing the specific switching operation, we need to understand a few concepts:

SSL/TSL

Regarding SSL/TSL, Ruan Yifeng’s two blog posts provide a good introduction:

  • Overview of SSL/TLS protocol operation mechanism

  • SSL/TLS Protocol Diagram

Simply put, SSL/TSL exchanges three pieces of information through a four-way handshake:

1. Digital certificate: This certificate contains information such as the public key. It is usually sent by the server to the client. The recipient determines whether the certificate is credible by verifying whether it is issued by a trusted CA or comparing it with the local certificate. If two-way authentication is required, both the server and the client need to send digital certificates to each other for verification.

2. Three random numbers: These three random numbers constitute the "session key" used to symmetrically encrypt and decrypt data in the subsequent communication process.

First, the client sends the first random number N1, and then the server replies with the second random number N2 (the previously mentioned certificate is also sent to the client during this process). Both random numbers are in plain text; and the third random number N3 (this random number is called the Premaster secret), the client uses the public key of the digital certificate to perform asymmetrical encryption and sends it to the server; and the server uses the private key known only to itself to decrypt and obtain the third random number. Only then, the server and the client have the three random numbers N1+N2+N3, and then both ends use these three random numbers to generate a "conversation key", and all subsequent communications use this "conversation key" for symmetric encryption and decryption. Because in this process, the server's private key is only used to decrypt the third random number and has never been transmitted on the network, so as long as the private key is not leaked, the data is safe.

3. Encrypted communication protocol: This means that both parties discuss which encryption method to use. If the encryption methods supported by the two parties do not match, communication will be impossible;

There is a common question: Why do we need three random numbers? Can't we just use the last random number N3?

This is due to the design of SSL/TLS, which assumes that the server does not believe that all clients can provide completely random numbers. If the random number provided by a client is not random, the risk of the "session key" being cracked is greatly increased. Therefore, the final random number is composed of three groups of random numbers to ensure the randomness of the random number, thereby ensuring the security of the "session key" generated each time.

Digital Certificates

A digital certificate is an electronic document that contains the holder's information, public key, and digital signature that proves the certificate is valid. Digital certificates and related public key management and verification technologies constitute the PKI (Public Key Infrastructure) specification system. Generally speaking, digital certificates are issued and managed by a digital certificate authority (CA), which is responsible for verifying the legitimacy of the public key in the PKI system. There are many types of digital certificates, and HTTPS uses SSL certificates.

How to verify that the digital certificate is issued by CA and not forged by a third party? Before answering this question, we need to understand the organizational structure of CA. First of all, in the CA organizational structure, the top level is the root CA, which can authorize multiple secondary CAs, and the secondary CA can authorize multiple tertiary CAs, so the organizational structure of CA is a tree structure. For the SSL certificate market, it is mainly divided by Symantec (which owns VeriSign and GeoTrust), Comodo SSL, Go Daddy and GlobalSign. After understanding the organizational structure of CA, let's take a look at the issuance process of digital certificates:

The CA, the issuing authority of the digital certificate, will check and verify the authenticity and validity of the information after receiving it from the applicant, and then produce a document that complies with the X.509 standard. The certificate content in the certificate includes the holder information and public key, which are all provided by the applicant, and the digital signature is obtained after the CA organization hashes the certificate content. This digital signature is the data we use to verify whether the certificate is issued by a trusted CA.

After receiving a digital certificate Cer1, the receiver hashes the certificate content to H1; then finds the public key in the digital certificate of CA1, the institution that issued the certificate, decrypts the digital signature on the certificate, and obtains the hash summary H2 signed by certificate Cer1; compares H1 and H2. If they are equal, it means that the certificate has not been tampered with. But at this time, it is still unknown whether the CA is legal. We can see that there is a digital certificate of the CA institution in the above figure. This certificate is public and can be obtained by everyone. The digital signature in this certificate is generated by the previous level, so it can be recursively verified until the root CA. The root CA is self-verified, that is, its digital signature is generated by its own private key. The legitimate root CA will be added to the authoritative trusted CA list by the browser and operating system, thus completing the final verification. Therefore, you must protect the root CA trust list in your environment (browser/operating system). Trusting the root CA means trusting all certificates issued by all sub-CAs under the root CA. Do not add the root CA certificate casually.

After understanding the above two concepts, you will have a preliminary understanding of HTTPS. Next, let's see how to implement support for HTTPS on iOS.

2. Implement support for HTTPS

First of all, you need to clarify the purpose of your use of HTTP/HTTPS, because OSX and iOS platforms provide a variety of APIs to support different purposes. The official document "Making HTTP and HTTPS Requests" has detailed instructions, and the document "HTTPS Server Trust Evaluation" explains the relevant knowledge of HTTPS verification in detail, so I won't go into details here. This article mainly explains how to implement HTTPS support for the most commonly used NSURLConnection (NSURLSession's implementation method is similar, but the callback for authorization proof is different), and how to use AFNetworking, a very popular third-party library, to support HTTPS. This article assumes that you have enough knowledge of HTTP and NSURLConnection interfaces.

API to verify certificates

The relevant API is in the Security Framework, and the verification process is as follows:

1). The first step is to obtain the trust object that needs to be verified. The way to obtain this Trust Object is different in different application scenarios. For NSURLConnection, it is obtained from the parameter challenge returned by the delegate method -connection:willSendRequestForAuthenticationChallenge: ([challenge.protectionSpace serverTrust]).

2). Use the system default verification method to verify the Trust Object. SecTrustEvaluate will verify the validity of each level of digital signature on the certificate chain (explained in the previous section) based on the verification strategy of the Trust Object, thereby evaluating the validity of the certificate.

3). If the second step of verification is passed, under general security requirements, it can be directly verified and enter the next step: use Trust Object to generate a credential ([NSURLCredential credentialForTrust:serverTrust]), pass it to the sender of challenge ([challenge.sender useCredential:cred forAuthenticationChallenge:challenge]) for processing and establish a connection.

4). If there are stronger security requirements, you can continue to perform stricter verification on the Trust Object. The common method is to import the certificate locally and verify whether the Trust Object matches the imported certificate. For more methods, see Enforcing Stricter Server Trust Evaluation, which will be explained in the explanation of AFNetworking source code.

5). If the verification fails, cancel the Challenge-Response Authentication verification process and reject the connection request.

ps: If the certificate is self-built, the second step will be skipped and the third step will be used for verification, because the digital signature of the root CA of the self-built certificate is not in the trust list of the operating system.

Now that we have a general understanding of the API and process of iOS authorization verification, let's take a look at the code implementation in NSURLConnection:

Using NSURLConnection to support HTTPS implementation

  1. // Now start the connection  
  2. NSURL * httpsURL = [NSURL URLWithString:@ "https://www.google.com" ];
  3. self.connection = [NSURLConnection connectionWithRequest:[NSURLRequest requestWithURL:httpsURL] delegate:self];
  4.      
  5. //Callback  
  6. - ( void )connection:(NSURLConnection *)connection willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge {
  7. //1) Get the trust object  
  8. SecTrustRef trust = challenge.protectionSpace.serverTrust;
  9. SecTrustResultType result;
  10.      
  11. //2)SecTrustEvaluate verifies trust  
  12. OSStatus status = SecTrustEvaluate(trust, &result);
  13. if (status == errSecSuccess &&
  14. (result == kSecTrustResultProceed ||
  15. result == kSecTrustResultUnspecified)) {
  16.          
  17. //3) Verification succeeds, generates NSURLCredential credential cred, and tells the sender of the challenge to use this credential to continue the connection  
  18. NSURLCredential *cred = [NSURLCredential credentialForTrust:trust];
  19. [challenge.sender useCredential:cred forAuthenticationChallenge:challenge];
  20.          
  21. } else {
  22.      
  23. //5) Verification failed, cancel this verification process  
  24. [challenge.sender cancelAuthenticationChallenge:challenge];
  25.          
  26. }
  27. }

The above code verifies the certificate through the system default verification process. What if we build our own certificate? In this case, the server certificate in the Trust Object is not issued by a trusted CA, so directly using SecTrustEvaluate for verification will not succeed. Or, even if the certificate returned by the server is issued by a trusted CA, how can we be sure that this certificate is the specific certificate we want? This requires first importing the certificate locally, setting it to the Anchor Certificate (that is, the root certificate) that needs to be verified, and then calling SecTrustEvaluate to verify. The code is as follows

  1. //Import the certificate first  
  2. NSString *cerPath = ...; //Certificate path  
  3. NSData * cerData = [NSData dataWithContentsOfFile:cerPath];
  4. SecCertificateRef certificate = SecCertificateCreateWithData(NULL, (__bridge CFDataRef)(cerData));
  5. self.trustedCertificates = @[CFBridgingRelease(certificate)];
  6. //Callback  
  7. - ( void )connection:(NSURLConnection *)connection willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge {
  8. //1) Get the trust object  
  9. SecTrustRef trust = challenge.protectionSpace.serverTrust;
  10. SecTrustResultType result;
  11. //Note: Here, set the previously imported certificate as the anchor certificate of the Trust Object verified below  
  12. SecTrustSetAnchorCertificates(trust, (__bridge CFArrayRef)self.trustedCertificates);
  13. //2)SecTrustEvaluate will look for the certificate set by SecTrustSetAnchorCertificates or the certificate provided by the system by default to verify the trust  
  14. OSStatus status = SecTrustEvaluate(trust, &result);
  15. if (status == errSecSuccess &&
  16. (result == kSecTrustResultProceed ||
  17. result == kSecTrustResultUnspecified)) {
  18.          
  19. //3) Verification succeeds, generates NSURLCredential credential cred, and tells the sender of the challenge to use this credential to continue the connection  
  20. NSURLCredential *cred = [NSURLCredential credentialForTrust:trust];
  21. [challenge.sender useCredential:cred forAuthenticationChallenge:challenge];
  22.          
  23. } else {
  24.      
  25. //5) Verification failed, cancel this verification process  
  26. [challenge.sender cancelAuthenticationChallenge:challenge];
  27.          
  28. }
  29. }

It is recommended to verify the certificate by importing the certificate locally to ensure adequate security. For more verification methods, please refer to the official document "HTTPS Server Trust Evaluation"

Using AFNetworking to support HTTPS

AFNetworking is one of the most popular third-party open source libraries for iOS/OSX development. Its author is Mattt Thompson, a very famous iOS/OSX developer. His blog NSHipster is also a good place for iOS/OSX developers to learn and broaden their technical horizons. AFNetworking has encapsulated the above logic code, and even more perfected it in the AFSecurityPolicy file. If you are interested, you can read the code of this module;

Configuring support for HTTPS on AFNetworking is very simple:

  1. NSURL * url = [NSURL URLWithString:@ "https://www.google.com" ];
  2. AFHTTPRequestOperationManager * requestOperationManager = [[AFHTTPRequestOperationManager alloc] initWithBaseURL:url];
  3. dispatch_queue_t requestQueue = dispatch_create_serial_queue_for_name( "kRequestCompletionQueue" );
  4. requestOperationManager.completionQueue = requestQueue;
  5. AFSecurityPolicy * securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeCertificate];
  6. //allowInvalidCertificates Whether to allow invalid certificates (that is, self-built certificates), the default is NO  
  7. //If you need to verify your own certificate, you need to set it to YES  
  8. securityPolicy.allowInvalidCertificates = YES;
  9. //validatesDomainName Whether to verify the domain name, the default is YES;  
  10. //If the domain name of the certificate is inconsistent with the domain name you requested, you need to set this item to NO  
  11. // Mainly used in this situation: the client requests a subdomain, but the domain name on the certificate is another domain name. Because the domain name on the SSL certificate is independent, if the domain name registered on the certificate is www.google.com, then mail.google.com cannot be verified; of course, if you have money, you can register a wildcard domain name *.google.com, but this is still relatively expensive.  
  12. securityPolicy.validatesDomainName = NO;
  13. //validatesCertificateChain whether to verify the entire certificate chain, the default is YES  
  14. //Set to YES to compare the certificate chain on the Trust Object returned by the server with the locally imported certificate. This means that if your certificate chain is like this:  
  15. //GeoTrust Global CA  
  16. // Google Internet Authority G2  
  17. // *.google.com  
  18. //Then, in addition to importing *.google.com, you also need to import all CA certificates in the certificate chain (GeoTrust Global CA, Google Internet Authority G2);  
  19. //If you build your own certificate, you can set it to YES to enhance security; if the certificate is issued by a trusted CA, it is recommended to turn off this verification;  
  20. securityPolicy.validatesCertificateChain = NO;
  21. requestOperationManager.securityPolicy = securityPolicy;

This is the main configuration description of AFNetworking's support for HTTPS. AFHTTPSessionManager is basically the same, so I won't repeat it.

3. Conclusion

Although HTTPS has certain performance disadvantages compared to HTTP, with the rapid development of the Internet and the exponential growth of mobile device performance, security is what we should consider more. HTTPS for the entire network is not that far away.

<<:  6 iOS Image Text Design Tips

>>:  Just read this article! 2015 Mobile UI/UX Design Trend Report

Recommend

When you go on a long trip, remember to turn off the gas!

□ Popular Science Times reporter Zhang Yingxian R...

How to write code that others can understand

With the continuous development of the software i...

How to Become a Great JavaScript Programmer

[[138028]] When I was a teenager, my interests sp...

Android Data Adapter Optimization: Efficient ViewHolder

When using Listview or GridView, a custom data ad...

How much does it cost to be an agent for a decoration mini program in Foshan?

Is it easy to be an agent of Foshan decoration mi...

Not a barber but a "nanny", revealing the "magical job" of zoo keepers

Not long ago, a lion with bangs became a hot topi...

Didi’s “Carpooling” product analysis report!

Didi created National Carpooling Day and launched...