Secure Secrets in Swift/UI

How do we store our secrets on the client-side? Are we really vulnerable to attacks? Is it really worthwhile to take the measures to store them securely?

Almost all the iOS apps have some secret keys to protect like:

  • API keys
  • Private Headers
  • Cryptographic Keys
  • Passwords

These keys are needed:

  • to set up third-party SDKs
  • to authenticate with backend APIs
  • to automate build process or to use in any developer tools, such as communicating to Apple Developer Account or App Store Connect

But imagine a situation, where they are compromised, for instance, if someone gets hold of our Firebase API key, now he/she can easily misuse or overuse our paid credentials if he/she is determined & skilled to hack into few other related keys.

Q: Are our keys really this vulnerable to attacks?

A: Yes & No
Yes: If we hardcode them in the source code or if we push them on the source control.
No: If we take some basic measures to secure them, also it takes little determination and a lot of skills from a hacker to extract or debug them from the binary.

Q: Is it really worthwhile to take the measures to store them securely?

A: Yes & No
Yes: Because they are our App Secrets
No: Because we can’t make it 100% hack-free

Be aware you should authenticate users, not authenticate an app. It’s mathematically impossible to hide data perfectly yet still be able to access it from your code.
- Chris Hulbert from Splinter

How do we store our secrets on the client-side?

There are various ways to do it, it’s covered beautifully in this NSHipster Article by Mattt. The most effective one is Obfuscating which is discussed in length by Chris Hulbert here & here.

We are going to discuss the easiest, yet quite effective Apple’s way, by using Xcode Configurations and Info.plist.

Step 1:
Add a New ConfigFile in the Project

Step 2:
Make sure you don’t check any Targets which is also the default in Xcode.

Step 3:
Let’s add an API Key in the Config.xcconfig

Step 4:
Add Config.xcconfig to the gitignore. This step is very important as we don’t want it to be available to everyone who has access to our repo.
If due to some reason our repo is compromised, the hacker won’t get hold of our secrets.

Step 5:
Let’s add the API Key to our info.plist. The API_KEY in our Config.xcconfig acts as a User-defined Variable which can be accessed by $(API_KEY) on the info.plist.

Step 6:
Let’s set the Config.xcconfig to the Configurations to our App Project.
You can always create different xcconfigs for Debug & Release, for simplicity of this article we will keep one.

Let’s do a simple check if we can access our API Key in the code.

let apiKey = (Bundle.main.infoDictionary?["API_KEY"] as? String)!

print(apiKey)

That should do it ✅

If this Article was useful to you, consider donating in crypto: 0xa543273edBb21F00BcC8c4327b8EEF03cF73b56E

With love and respect,
Arturo 👨🏻‍💻