Do’s | Dont’s |
---|---|
Include a Backup Cert Pin. (Retain app connectivity if new keys on server are used or the CA is changed). |
Pin the full certificate. (The full cert, and potentially backup certs are available for inspection, the certificate is bundled with the app meaning that when a cert expires the app must be rebuilt with a new cert). |
Perform Certificate Pinning using the hash of the public key - SubjectPublicKeyInfo of the X.509 certificate. (Allows you to anonymize a certificate or public key and ensures an attacker does not see the reserved certificate or public key in advance of its use). |
Send sensitive data without certificate pinning. (Creates higher risk as an attacker with network privileges, or who has compromised TLS, is better positioned to intercept data). |
Perform proper certificate validation if the platform doesn’t allow true certificate pinning. (Adds an extra precautionary check when sending sensitive data). |
Establish connections with endpoints that offer a different certificate or key, even if signed by a trusted CA. (The channel is not trusted.) |
Use TLS for network encryption. (SSL 2.0 and 3.0 have been deprecated by the IETF). |
Use Mixed SSL sessions. (The users session ID can be exposed over non HTTPS requests). |
Use a secure channel consistently throughout the app. (Ensure that some network calls are not sent in plaintext). |
Use localhost network ports for handling sensitive IPC. (The interface is accessible by other applications on the device). |
Verify that the app doesn’t rely on a single insecure communication channel such as email or SMS for critical operations, such as enrollments and account recovery. (Use a hardware token or secure channel as GCM or Apple Push notifications). |
Don’t rely on unauthenticated SMS data to perform sensitive commands. (The input may be malicious, be spoofed or sniffed using another app with SMS read permissions). |
Verify that the app uses some form of whitelisting to control access to external domains. (Limit the outbound requests to predefined trusted domains). |
Avoid sending crash logs over the network in plaintext. (Logs can contain sensitive or important information about the user and/or the application). |
Pay particular attention to validating all data received from and sent to non-trusted third party apps/plugins before incorporating their use into an application. (Some plugins can interact with ad networks etc). |
|
Consider using HTTP Strict Transport Security (HSTS). (Protect against protocol downgrade attacks and cookie hijacking). |
|
Make sure that you don’t trust data downloaded from HTTP or other insecure protocols. (Validate the data before using it in an application). |
|
Require User Approval before Executing a Function that Transmits PII over a Network. (Inform the user that their data is being transferred over a network or being sent to another location). |
|
For highly sensitive values, implement additional encryption in transit. (Improved protection in case the secure channel somehow compromised). |
A number of features were added to enhance the security of the channel between the Mobile App and the Authentication or API Server.
The main code logic for certificate pinning is found under here in the CertPinningHelper class.
Certificate Pinning has been implemented in the Application using the SPKI technique. This ensures easier maintenance and improved security by anonymizing the certificate information in the application. The TrustKit Android library is being utilised to allow certificate pinning to work with older API levels.
The Android Network Security Configuration XML file defined the pins of the server you want to pin against.
link:https://raw.githubusercontent.com/aerogear/android-showcase-template/master/app/src/main/res/xml/network_security_config.xml[role=include]
You can get the pin for a website using OpenSSL:
openssl s_client -servername www.example.com -connect www.example.com:443 | openssl x509 -pubkey -noout | openssl pkey -pubin -outform der | openssl dgst -sha256 -binary | openssl enc -base64
A HTTP request function has been created to perform requests to the Authentication servers. The createRequest()
functions performs pinning verification on the requests.
link:https://raw.githubusercontent.com/aerogear/android-showcase-template/master/app/src/main/java/com/aerogear/androidshowcase/mvp/components/CertPinningHelper.java[role=include]
A function has also been provided to check if the OkHTTP callback failure exception was due to a certificate validation issue.
link:https://raw.githubusercontent.com/aerogear/android-showcase-template/master/app/src/main/java/com/aerogear/androidshowcase/mvp/components/CertPinningHelper.java[role=include]
When remote APIs are being invoked, before sending the data, you should make sure the client does have the required permission. If the client doesn’t have the required permission, the client should not perform the request at all:
link:https://raw.githubusercontent.com/aerogear/android-showcase-template/master/app/src/main/java/com/aerogear/androidshowcase/features/network/presenters/UploadNotesPresenter.java[role=include]
However, just checking the permission on the client is not enough. You should always check the user permission on the backend API server as well:
link:https://raw.githubusercontent.com/feedhenry/mobile-security/master/projects/api-server/index.js[role=include]
You should also perform certificate pinning checks when calling remote APIs:
link:https://raw.githubusercontent.com/aerogear/android-showcase-template/master/app/src/main/java/com/aerogear/androidshowcase/features/network/presenters/UploadNotesPresenter.java[role=include]
The Certificate Pinning Service and the AppDelegate contain the main code for configuring and performing certificate pinning. The TrustKit library is being used to perform SPKI Certificate Pinning. The pin is a Base64 encoded Subject Public Key Information fingerprint from an X.509 Certificate.
You can get the pin for a website using OpenSSL:
openssl s_client -servername www.example.com -connect www.example.com:443 | openssl x509 -pubkey -noout | openssl pkey -pubin -outform der | openssl dgst -sha256 -binary | openssl enc -base64
TrustKit can be configured and initialised from the AppDelegate file. TrustKit is configured below to perform swizzling of the App’s NSURLConnection and NSURLSession delegates in order to automatically add pinning validation to the App’s HTTPS connections.
link:https://raw.githubusercontent.com/aerogear/ios-showcase-template/master/secure-ios-app/AppDelegate.swift[role=include]
The performValidCertCheck()
function in the Certificate Pinning Service can be used to manually check if a request to a host fails due to certificate pinning validation issues.
link:https://raw.githubusercontent.com/aerogear/ios-showcase-template/master/secure-ios-app/services/CertPinningService.swift[role=include]
The outcome of the certificate checks can then be used to warn the user if a secure channel is not available. In the example below, pinning is performed when the authentication button is pressed. If there are certificate validation issues, the end user will not be allowed to authenticate and the UI is updated to warn them that their connection to the remote server is not secure.
link:https://raw.githubusercontent.com/aerogear/ios-showcase-template/master/secure-ios-app/authentication/AuthenticationViewController.swift[role=include]
Certificate Pinning is being performed on preflight requests to ensure that the channel is secure before sending sensitive data.
link:https://raw.githubusercontent.com/feedhenry/mobile-security-cordova-template/c24297cda240efa40aca292e7d0657d7432d1eba/src/pages/auth/auth.ts[role=include]
The pinning fingerprint is defined in the /config/keycloak.json file.
link:https://raw.githubusercontent.com/feedhenry/mobile-security-cordova-template/c24297cda240efa40aca292e7d0657d7432d1eba/src/config/keycloak.json[role=include]