It can be seen over and over again: API-keys are directly embedded in the source code of an app. The most recent incident as of February 2020 is the Iowa caucus app, that contained API-keys right inside the source code.
But it should be clear, that source code or the corresponding assembly/binary/bytecode is not secure storage for credentials, especially when rolled out to the end-users' device! Hardcoding API credentials into the source code is a no-go. There are at least two reasons:
- Source code may be uploaded to a public repository (e.g. GitHub). By the time it is uploaded, the uploader may not be aware of the credentials being included in the sources.
- Assembly/binary/bytecode can be easily disassembled/decoded and any API-keys can be easily extracted.
If source code and the resulting assembly/binary/bytecode are not a secure place for API credentials, how should API credentials be persisted instead?
There are several aspects to the answer:
- Static credentials such as API-keys should not be used in the first place. Instead, dynamic credentials should be used. This needs to be fixed by the API provider. See section "Static vs Dynamic Credentials".
- Where credentials are stored. Not in assembly/binary/bytecode, but in secure storage. This needs to be properly managed by the API consumer. See the section "Credential Storage".
API-keys are static credentials and thus can be easily transferred and used in unintended scenarios. They do not even adequately identify the app. And under no circumstances should access to user-data be made, based on an API-key.
This is a problem, that first of all needs to be addressed by the API provider. The API provider needs to offer APIs protected by dynamic credentials. Dynamic credentials, such as OAuth, require to include the end-user in the loop, who has to authenticate. And the end-user should be able to check the trustworthiness/authenticity of the app.
Dynamic credentials typically have several components, (1) identification of the app with a static credential, called clientID and clientSecret in OAuth, and (2) the end-user identification. The static credentials of the app should be stored in secure credential storage, offered by the operating system (see next section). If the end-user also decides to store end-user credentials, they should also be stored in secure credential storage.
If the API provider did their homework and protected the APIs with OAuth, it is now the turn of the API consumer to store the necessary credentials appropriately.
Apps should use the secure storage offered by the operating system to store app identifiers/credentials and user identifiers/credentials.
Both iOS and Android have appropriate libraries:
I hope to have shown you, more secure alternatives to protect your APIs and how to protect API credentials in your apps. The centerpiece? Use OAuth. Correctly.