preface

Using secure HTTPS connections when interacting with servers and Web services is an important step for security-sensitive data. By default, Alamofire uses the validation method built into Apple’s security framework to validate the certificate chain provided by the server. Although the certificate chain is effective, it cannot prevent man-in-the-middle attacks. To reduce man-in-the-middle attacks, the ServerTrustPolicy should be used for certificate authentication when processing sensitive data of users.

The security policy

ServerTrustPolicy = ServerTrustPolicy = ServerTrustPolicy = ServerTrustPolicy

let urlString = "https://47.105.168.156:20199/users/bar"
SessionManager.default.request(urlString).response { (responseString) in
    print(responseString)
}
Copy the code

And here’s the result:

plist
Allow Arbitrary Loads
YES
https://47.105.168.156:20199/users/bar

Since all network requests go through the SessionDelegate callback, there is a method in the sessionDelegate. swift file that looks like this:

taskDidReceiveChallenge
TaskDelegate
TaskDelegate.swift

let serverTrustPolicy = session.serverTrustPolicyManager? .serverTrustPolicy(forHost: host),

If YOU click on serverTrustPolicyManager and you see that it’s an associated property of URLSession, when was this serverTrustPolicyManager passed in?

Since it is an associated property of URLSession, take a look at the SessionManager from the example above 🌰. In the initialization method of the SessionManager, you can see,

serverTrustPolicyManager
SessionManager
ServerTrustPolicyManager

Open Class ServerTrustPolicyManager {// Trust policy array openletPolicies: [String: ServerTrustPolicy] Public init(policies: [String: ServerTrustPolicy]) {self.policies = policies} open func ServerTrustPolicy (forHost host: String) -> ServerTrustPolicy? {
        return policies[host]
    }
}
Copy the code

If we think of ServerTrustPolicy as a security policy, we mean the policy adopted for a server. So the ServerTrustPolicyManager is the administrator for the ServerTrustPolicy. However, in the real world, an APP may use many different host addresses. Hence the need to bind a specific security policy to each host address. Therefore, The ServerTrustPolicyManager needs a dictionary to hold these host addresses, along with the security policies for the corresponding points. We already know that ServerTrustPolicyManager is an associated property of URLSession, so it is bound directly to URLSession

Since there are multiple security trust policies, it is obvious that ServerTrustPolicy is an enumerated type:

Public enum ServerTrustPolicy {// The default policy is executed and the certificate passes the verificationcasePerformDefaultEvaluation (validateHost: BoolcasePerformRevokedEvaluation (validateHost: Bool, revocationFlags: CFOptionFlags) // Certificate verification policy, which uses certificates to verify server trustcasepinCertificates(certificates: [SecCertificate], validateCertificateChain: Bool, validateHost: Bool) // Public key authentication policy, which uses public keys to verify server trustcasePinPublicKeys (publicKeys: [SecKey], validateCertificateChain: Bool, validateHost: Bool) / / disable strategy, don't do any validation (heart really big...).case disableEvaluation // User-defined policy. Returns a BOOLcaseCustomEvaluation ((_ serverTrust: SecTrust, _ host: String) -> Bool)...... }Copy the code

With that in mind, it’s time to initialize a SessionManager:

 let urlString = "https://47.105.168.156:20199/users/bar"
 let serverTrustPolicies: [String: ServerTrustPolicy] = [
            urlString: .pinCertificates(
                certificates: ServerTrustPolicy.certificates(),
                validateCertificateChain: true,
                validateHost: true)]let sessionManager = SessionManager(serverTrustPolicyManager: ServerTrustPolicyManager(policies: serverTrustPolicies))
sessionManager.request(urlString).response { (responseString) in
    print(responseString)
}
Copy the code

That will do. 😏 😼 😼

ServerTrustPolicy

From the above ⤴️⤴️⤴️ we have an overview of the ServerTrustPolicy enumeration class. Of its six validation policies, let’s take a look at two of the more common ones:

pinCertificates

PinCertificates is a certificate authentication policy. It means that the client will verify all the contents of the certificate returned by the server and the locally saved certificate. If the verification is correct, the client will continue to execute the certificate.

pinCertificates(certificates: [SecCertificate], validateCertificateChain: Bool, validateHost: Bool)
Copy the code

1️ parameter 1: Certificates represent certificates

2️ parameter 2: validateCertificateChain represents whether to verify the certificate chain

3️ parameter 3: validateHost represents whether to verify the sub-address

So if you need to pass in the certificate, how do you find the certificate file? There is a method called Certificates in ServerTrustPolicy:

certificates

In actual development, if the server needs to be verified during the secure connection with the server, it is a good way to save some certificates locally, and then get the certificate sent from the server, and then compare and verify. If the verification is successful, it means that the server can be trusted. As you can see from the above function, Alamofire looks for certificates in the Bundle with the suffix “.cer”, “.cer”, “.crt”, “.crt”, “.der”, “.der”

pinPublicKeys

PinPublicKeys PublicKey authentication policy: the client verifies the PublicKey in the certificate returned by the server and the local certificate only when the verification is correct.

case pinPublicKeys(publicKeys: [SecKey], validateCertificateChain: Bool, validateHost: Bool)
Copy the code

1️ parameter 1:publicKeys indicates the public key

2️ parameter 2: validateCertificateChain represents whether to verify the certificate chain

3️ parameter 3: validateHost represents whether to verify the sub-address

Similarly, ServerTrustPolicy has a method called publicKeys to find the publicKeys of all certificates in the root directory

Here explain validateCertificateChain verification certificate chain, if there is no configured server certificate chain, so will not be able to verify the certificate chain, can verify, can directly cancel the validation.

Validation process

Has to verify the content of the above strategy to know about, now look back to the beginning, we know the let serverTrustPolicy = session. ServerTrustPolicyManager? ServerTrustPolicy (forHost: host), this condition is not true, so the validation fails. Now what happens when you change the validation policy, the code continues to see what happens?

evaluate
serverTrust
host

evaluate
switch
case
evaluate
host

As can be seen from the above section, there are three steps to complete the verification under normal authentication strategy:

1️ : SecPolicyCreateSSL Create policy, whether to verify host

2️ : SecTrustSetPolicies on setting policies for the object SecTrust to be verified

3️ : trustIsValid for verification

conclusion

In actual development projects, there may be a lot of companies to buy CA certificates, which may not need to be verified at the time of request. However, for self-certification documents, we can conduct verification according to our own development requirements, among which the most secure is certificate chain plus host double verification. The security authentication policy ServerTrustPolicy of Alamofire is known here. If there is an error, please correct it!