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!