This mechanism is called SSL Pinning.
Theory:
What is Pinning? .
Pinning is an optional mechanism that can be used to improve the
security of a service or site that relies on SSL Certificates. Pinning
allows you to specify a cryptographic identity that should be accepted
by users visiting your site.
That sounds complex, but it’s actually pretty simple. Let’s start by
breaking down that down:
A cryptographic identity is a file that can prove the identity of a
server/host through cryptography. An SSL certificate, a public key,
and a CSR are all examples of a cryptographic identity. That pin would
then tell the client to remember that identity (or identities) and
only accept those when establishing future secure connections.
So, if you wanted to use pinning, you would configure your server (in
some situations – think internal systems – you may also configure the
clients) and specify what you wanted to pin. Browsers and other
clients would evaluate the pinned identity on every connection. If any
other identity was presented, the client would abort the connection
(which was happened in your case with Charles Proxy).
To think big picture: an SSL connection tells the client to make an
encrypted connection with any identity matching that host. Pinning
tells the client a specific identity they should accept when making a
secure connection.
So, for example, if our site is example.com, we could pin an identity.
When a user visits our site, they would receive the pinned
information. On a future visit, their browser would take action if we
tried to get the client to use a different identity.
Practice:
The main key of SSL pinning that server certificate will be saved in app bundle. Then, when client receives certificate from server, it then compares 2 certificates to make sure that they are the same before establishing the connection.
The Alamofire HTTP networking library has the built-in function for SSL pinning and very easy to use:
let pathToCert = Bundle.main.path(forResource: "name-of-cert-file", ofType: "cer")
let localCertificate: NSData = NSData(contentsOfFile: pathToCert!)!
let serverTrustPolicy = ServerTrustPolicy.pinCertificates(
certificates: [SecCertificateCreateWithData(nil, localCertificate)!],
validateCertificateChain: true,
validateHost: true
)
let serverTrustPolicies = [
"my-server.com": serverTrustPolicy
]
let sessionManager = SessionManager(
serverTrustPolicyManager: ServerTrustPolicyManager(policies: serverTrustPolicies)
)
You can read more here and here about how to achieve SSL Pinning in your swift app.