Most of the services your application interacts with require authentication. Authentication through a secret, an API key or a client secret, is a commonly used method. Your application includes the secret in the request it sends to the service. That is only possible if your application has access to the secret at runtime.
Protecting Secrets
How does your application obtain the secret? There are several options to choose from. You can hard-code the secret or you can include it in the application's Info.plist as I outline in Injecting Base URL and API Key. Another option is fetching the secret from a remote server. No matter what option you pick, the secret can be obtained by bad actors. That is the reality.
Each of the aforementioned options has its pros and cons. Hard-coding the secret is easy and convenient from the point of view of the developer, but it isn't a flexible solution. Bad actors can extract the secret from your application's binary with relative ease. If you revoke the secret to limit the damage, you need to ship a new version of your application that includes a new secret. That takes time and it doesn't resolve the vulnerability.
The same is true if the secret is stored in your application's Info.plist. Fetching the secret key from a remote server is more secure and much more flexible, but how can your application securely fetch the secret from the remote server? It would need to authenticate itself with the remote server to prevent anyone but your application from accessing the secret. How would it authenticate itself with the remote server? Another secret?
Prepare for the Worst
The secrets your application has access to can be extracted by bad actors. That is a possibility you need to accept and, more important, prepare for. You can prepare for this event in several ways. Let me show you a solution in which your application doesn't need access to those secrets.
Protecting Secrets with a Proxy Server
Using a proxy server to protect secrets is a solution I have used in several projects. It adds complexity to the project, but that complexity opens up a number of interesting possibilities. Let me explain how it works and what the benefits are.
The idea itself isn't complex. Your application doesn't interact with the service. It sends a request to the proxy server instead. The proxy server forwards the request to the service and the proxy server forwards the response of the service to your application. This means that your application no longer needs access to the secret that is required to interact with the service.
It is the proxy server that sends the request to the service on behalf of your application and it is the proxy server that requires access to the secret. The risk the proxy server leaks the secret is much smaller because it is under your control. Anyone can download an application from Apple's App Store and extract its secrets. That isn't true for a proxy server you operate and control.
Benefits of a Proxy Server
A proxy server has several more benefits and this is the point where things get as complex as your project's needs.
Rotating Secrets
A proxy server can be more than just a server that forwards requests to one or more services. It can be used as a vendor of secrets. Instead of embedding a secret into the client, the latter asks for a secret with a short lifetime or time to live (TTL). If the secret is compromised, the damage is limited due to the short lifetime of the secret. By rotating keys regularly, you have much more control over the impact a compromised secret has on your business.
Client- and Platform-Specific Secrets
You can further reduce the impact of a compromised secret by vending secrets that are client- or platform-specific. Let me give you an example. The proxy server issues a secret to a client that enables the latter to interact with a service. The proxy server inspects the request of the client and vends a platform-specific secret. If a secret is compromised, the impact of rotating the platform-specific secret is limited to the platform the secret was issued for.
You can take it one step further and link a secret to a client. If a secret is compromised, you only need to rotate the secret of that client. This has a few benefits. The obvious benefit is a much smaller impact on the user experience as only one client is impacted. The less obvious benefit is that you can make it much easier to figure out how the secret was exposed because you can trace it back to a specific client.
Decoupling Dependencies
Another nice benefit of a proxy server is that you can decouple your application from the services it depends on. Let's say your application fetches weather data from a weather service. By using a proxy server, you can replace the weather service with another weather service without your application knowing about it. This of course assumes that the response the proxy server returns to the client remains unchanged, which is something the proxy server can take care of.
Moving from one service to another can be incredibly costly for a company. It can sometimes take weeks, months, or years to complete such a transition, costing thousands of engineering hours. Taking such risks into account upfront can save the company a lot of time and money.
Performance
A proxy server can impact performance, both positively and negatively. It can positively impact performance by caching requests to the service that are frequently made. This is especially interesting if the service itself isn't performant or if you pay for every request you make to the service.
Important Caveats
There are a few caveats you need to carefully consider if you plan to use a proxy server to protect your application's secrets.
Throughput
Let's say your application uses Algolia for search. If your application sends a request for every keystroke, then your proxy server needs the ability to handle that volume of requests. Services like Algolia are built to handle large volumes of requests and keep response times low. Can your proxy server do the same?
Performance
Closely related to throughput is performance. Even if your proxy server has no problem serving hundreds or thousands of requests per minute, what does performance look like? If your proxy server becomes a bottleneck, then that can become problematic for the user experience of your application.
Availability
Modern, high-performing services are distributed and have redundancy built into them. That is what makes them highly available. It is unlikely that your proxy server can compete with that offering. Is that a problem or is that an acceptable compromise to improve your infrastructure's security?
Finding the Middle Ground
Speaking of compromises, there is a middle ground to be found. A proxy server is flexible and it is up to you to decide how you put it to use. For example, you can use a proxy server to vend secrets for the service your application interacts with. Modern services provide APIs to request secrets with a predefined set of permissions. A proxy server can take on the responsibility to vend secrets for such services. Your application would still directly interact with the service, but the secret would be provided by the proxy server. You could still have the ability to rotate secrets quickly and easily because they aren't embedded into the client.
Analyze your project's needs and identify its weaknesses. Prepare for the worst and, more important, create a plan of action when things go south.