preface

In the era of the rapid development of the Internet, basically every day with the network. So, how to ensure the security of information in network communication? In this article, we will talk about how Alamofire, as an excellent third-party library related to network requests in iOS development, is designed and used in its security policy.

Introduction of HTTPS

Before getting to the point, let’s take a quick look at HTTPS. If you already know, you can skip this paragraph.

Why use HTTPS

In the past, we used HTTP more, so why is Apple pushing us to use HTTPS as a more secure form of request? Problems with HTTP:

  1. Communications are in plain text, making them easy to eavesdrop on
  2. Do not verify the identity of the communication parties, easy to be disguised
  3. Data integrity cannot be verified and may be tampered with

Using the HTTPS communication mechanism can effectively prevent these problems. HTTPS is not a new protocol at the application layer, but the HTTP communication interface is replaced by SSL and TLS. Usually HTTP communicates directly with TCP, but when SSL is used, it communicates first with SSL and then with SSL and TCP. In short, HTTPS is HTTP in the shell of the SSL protocol.

HTTP+ Data Encryption + IDENTITY Authentication + Data integrity protection =HTTPS

HTTPS Encryption

HTTPS uses the hybrid encryption mechanism, that is, shared secret key encryption (symmetric encryption) and public key encryption (asymmetric encryption). Public key encryption is used in the key exchange process, and shared key encryption is used in the communication exchange message establishment stage. Public-key encryption is more secure than shared key encryption, so why not all public-key encryption? Because compared with shared secret key encryption, processing is more complex and slower. HTTPS combines the advantages and disadvantages of the two encryption methods to achieve a hybrid encryption process. As shown in the figure:

HTTPS authentication and encryption processes

HTTPS has one-way authentication and two-way authentication. The principles are basically the same. Here is the whole process of one-way authentication.

  1. Client initiatingHTTPSRequest: the client sends a request to the serverSSLProtocol version, encryption algorithm type, and random number.
  2. Server configuration: YesHTTPSThe protocol server must have a set of digital certificates, which can be made by yourself or applied to the organization. The difference is that a certificate issued by the client can be accessed only after the certificate is authenticated by the client, while a certificate applied for by a trusted company can be accessed directly. The certificate is a pair of public and private keys.
  3. Transfer certificate: This certificate is essentially a public key, but contains a lot of information, such as the certificate authority, expiration date, and so on. The server also sends messages to the clientSSLProtocol version, encryption algorithm type, and random number
  4. Client parsing certificates: This part of the job is done by the clientTLSFirst, it verifies whether the public key is valid, such as the authority, expiration date, etc. If an exception is found, it will throw a warning indicating that there is a problem with the certificate. If there is nothing wrong with the certificate, a random value is generated and then encrypted with the certificate.
  5. Transmit encrypted information: This part transmits the random value encrypted with the certificate. The purpose is to let the server get the random value, and the communication between the client and the server can be encrypted and decrypted by this random value.
  6. Service segment decryption information: after decrypting with the private key, the server gets the random value (private key) from the client, and then encrypts the content symmetrically through this value.
  7. Transfer encrypted information: This part of the information is the service segment encrypted with the private key, can be restored on the client.
  8. Client decryption message: The client decrypts the message sent by the service segment with the previously generated private key, and then obtains the decrypted content. Even if the third party listens to the data, there’s nothing they can do about it.

Alamofire safety certification

Certificate Authentication mode

We need to carry out security certification if the certificate is issued by the CA organization, and we do not need to write relevant codes for security certification. Here’s an example of Alamofire initiating an HTTPS request 🌰 :

let serverTrustPlolicies: [String: ServerTrustPolicy] = [
    hostUrl: .pinCertificates(
        certificates: ServerTrustPolicy.certificates(),
        validateCertificateChain: true,
        validateHost: true)]self.sessionManager = SessionManager(serverTrustPolicyManager: ServerTrustPolicyManager(policies: serverTrustPlolicies))
self.sessionManager? .request(urlString).response { (defaultResponse)in
    print(defaultResponse)
}
Copy the code
  • It is also very simple to useHTTPCompared to just initializingSessionManagerOne was passed in whenServerTrustPolicyManagerObject, which is the manager of the certificate trust policy.
  • Initialize theServerTrustPolicyManagerObject is passed in a[String: ServerTrustPolicy]A collection of types is saved as a parameter,keyIs the host address,valueValidation mode.
public enum ServerTrustPolicy {
    case performDefaultEvaluation(validateHost: Bool)
    case performRevokedEvaluation(validateHost: Bool, revocationFlags: CFOptionFlags)
    case pinCertificates(certificates: [SecCertificate], validateCertificateChain: Bool, validateHost: Bool)
    case pinPublicKeys(publicKeys: [SecKey], validateCertificateChain: Bool, validateHost: Bool)
    case disableEvaluation
    case customEvaluation((_ serverTrust: SecTrust._ host: String) - >Bool)}Copy the code
  • AlamofireThere are six modes of security authentication policy. The three modes are most commonly used:.pinCertificatesCertificate verification mode,.pinPublicKeysPublic key authentication mode and.disableEvaluationDo not validate schemas.
    • .performDefaultEvaluationBy default, only valid certificates can pass authentication
    • .performRevokedEvaluationAn additional setting for deregistering certificates
    • .pinCertificatesIn certificate verification mode, the client verifies the certificate returned by the server and the local certificate. If the certificate is correct, the client continues to perform the verification.
    • .pinPublicKeysIn PublicKey authentication mode, the client verifies the PublicKey in the certificate returned by the server and the locally saved certificate. If the certificate is correct, the client continues to perform the verification.
    • .disableEvaluationValidation under this option is always passed, unconditional trust.
    • .customEvaluationCustom validation, which returns a Boolean result.
  • This is used in the previous example.pinCertificatesCertificate authentication mode. It has three associated values:
    • Parameter 1:certificatesIt stands for certificate
    • Argument 2:validateCertificateChainIndicates whether to validate the certificate chain
    • Parameter 3:validateHostIndicates whether the child address is verified
  • So, how do we find the certificates in the project?AlamofireGives us a way to do itServerTrustPolicy.certificates()Easy to use.
public static func certificates(in bundle: Bundle = Bundle.main)- > [SecCertificate] {
    var certificates: [SecCertificate] = []

    let paths = Set([".cer".".CER".".crt".".CRT".".der".".DER"].map { fileExtension in
        bundle.paths(forResourcesOfType: fileExtension, inDirectory: nil)
    }.joined())

    for path in paths {
        if
            let certificateData = try? Data(contentsOf: URL(fileURLWithPath: path)) as CFData.let certificate = SecCertificateCreateWithData(nil, certificateData)
        {
            certificates.append(certificate)
        }
    }

    return certificates
}
Copy the code
  • The default is inBundle.mainWe can also specify where to store the certificateBundleTo find.
  • Now that you understand the validation pattern, take a look at the validation process. When a request is made, a callback is madeURLSessionTaskDelegateThe following method of.
open func urlSession(
    _ session: URLSession,
    task: URLSessionTask,
    didReceive challenge: URLAuthenticationChallenge,
    completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void)
{
    guard taskDidReceiveChallengeWithCompletion == nil else{ taskDidReceiveChallengeWithCompletion? (session, task, challenge, completionHandler)return
    }

    if let taskDidReceiveChallenge = taskDidReceiveChallenge {
        let result = taskDidReceiveChallenge(session, task, challenge)
        completionHandler(result.0, result.1)}else if let delegate = self[task]? .delegate { delegate.urlSession( session, task: task, didReceive: challenge, completionHandler: completionHandler ) }else {
        urlSession(session, didReceive: challenge, completionHandler: completionHandler)
    }
}
Copy the code
  • If you have any value taskDidReceiveChallengeWithCompletion, direct callback the closure, this means that we can achieve our validation logic. As you can see, Alamofire is very friendly, providing both regular implementations and developer custom implementations.

  • Continue tracing the code into the delegate.urlSession method

  • It then executes the method shown in the red box, retrieves the validation mode set earlier, and then executes the Evaluate method

public func evaluate(_ serverTrust: SecTrust, forHost host: String) -> Bool {
    var serverTrustIsValid = false

    switch self {
    // omit cannot code.....
    case let .pinCertificates(pinnedCertificates, validateCertificateChain, validateHost):
        if validateCertificateChain {
            let policy = SecPolicyCreateSSL(true, validateHost ? host as CFString : nil)
            SecTrustSetPolicies(serverTrust, policy)

            SecTrustSetAnchorCertificates(serverTrust, pinnedCertificates as CFArray)
            SecTrustSetAnchorCertificatesOnly(serverTrust, true)

            serverTrustIsValid = trustIsValid(serverTrust)
        } else {
            let serverCertificatesDataArray = certificateData(for: serverTrust)
            let pinnedCertificatesDataArray = certificateData(for: pinnedCertificates)

            outerLoop: for serverCertificateData in serverCertificatesDataArray {
                for pinnedCertificateData in pinnedCertificatesDataArray {
                    if serverCertificateData == pinnedCertificateData {
                        serverTrustIsValid = true
                        break outerLoop
                    }
                }
            }
        }
    // omit cannot code.....
    return serverTrustIsValid
}
Copy the code
  • If you need to validate the certificate chain, it will do soifCode block, roughly as follows:
    • SecPolicyCreateSSL: Creates a policy and specifies whether to verify host
    • SecTrustSetPolicies: Sets the policy for the object to be verified
    • trustIsValid: Verification is performed. The system returns successfullyYES
  • If you need to validate the certificate chain, the server certificate and your own certificate are processed into a binary array of certificates and compared.
  • If the validation passes, the normal request for data can begin; if the validation fails, the request is terminated and an exception is thrown.

Public key authentication mode

  • Public key authentication is similar to certificate authentication.pinPublicKeysThis enumeration value, the first parameter is the public key, the other parameters are the same as the certificate authentication mode.AlamofireIt also provides us with a method to obtain public keysServerTrustPolicy.publicKeys()Call this method directly.
  • So when do you use public key authentication? The advantage of using public key authentication mode is that as long as the public key remains unchanged, you can use it all the time without updating the certificate or worrying about the expiration of the certificate.

conclusion

This article briefly discusses the HTTPS encryption process, and analyzes the interface and network challenge process by how Alamofire requests HTTPS. Of course, you need to learn more if you want to fully understand how HTTPS works. I recommend a book called Diagrams of HTTP, which is very easy to read and some of the images in this article come from this book.


If you have any questions or suggestions, you are welcome to comment or write to us. Like friends can click on the following and like, the follow-up will continue to update the article.