In iOS, How to Store a Secret "Key" That Will Allow Me to Communicate with My Server

In iOS, how can I store a secret key that will allow me to communicate with my server?

Crazy as it sounds, this is probably the best solution. Everything else is more complicated, but not much more secure. Any fancy obfuscation techniques you use are just going to be reverse engineered almost as quickly as they'll find this key. But this static key solution, while wildly insecure, is nearly as secure than the other solutions while imposing nearly no extra complexity. I love it.

It will be broken almost immediately, but so will all the other solutions. So keep it simple.

The one thing that you really want to do here is use HTTPS and pin your certificates. And I'd pick a long, random key that isn't a word. Ideally, it should be a completely random string of bytes, stored as raw values (not characters) so that it doesn't stand out so obviously in your binary. If you want to get crazy, apply a SHA256 to it before sending it (so the actual key never shows up in your binary). Again, this is trivial to break, but it's easy, and won't waste a lot of time developing.

It is unlikely that any effort longer than an hour will be worth the trouble to implement this feature. If you want lots more on the topic, see Secure https encryption for iPhone app to webpage and its links.

iOS API Key: Is there an actual safe way to secure your API key when making http requests?

As already pointed out by @jake you should use a token tied up only to the user instead of an Api Key for all users, but other enhancements can be done for further protect your App when doing the http requests.

The user token can be a signed JWT token and then you can enhance the security of the communication between your server and the App with Certificate Pinning in order to protect against Man in the Middle Attacks.

Other techniques like the use of OAUTH2 and hiding secrets can be used to enhance the security of your App and you can read more about it here.

Keep in mind that Certificate Pinning can be bypassed by hooking frameworks such as Xposed that contain modules specific to bypass the pinning, but still another layer of security that you should not discard once it will increase the effort necessary to hack your App on the device and will protect your App against Man in the Middle Attacks.

For ultimately security between your App and the back-end you should use an App integrity attestation service, that will guarantee at run-time that your App was not tampered or is not running in a rooted device by using an SDK integrated in you App and a service running in the cloud.

On successful attestation of the App integrity a JWT token is issued and signed with a secret that only the back-end of your App and the attestation service in the cloud are aware and on failure the JWT is signed with a fake secret that the App back-end does not know, allowing this way for the App back-end to only serve requests when it can verify the signature in the JWT token and refuse them when it fails the verification.

Once the secret used by the cloud attestation service is not known by the App it is not possible to reverse engineer it at run-time even when the App is tampered, running in a rooted device or communicating over a connection that is being the target of a Man in the Middle Attack.

You can find such a service in Approov that have SDKs for several platforms, including IOS. The integration will also need a small check in the App back-end code to verify the JWT token in order the back-end can protect itself against fraudulent use.

JWT Token

Token Based Authentication

JSON Web Tokens are an open, industry standard RFC 7519 method for representing claims securely between two parties.

Certificate Pinning

Pinning is the process of associating a host with their expected X509 certificate or public key. Once a certificate or public key is known or seen for a host, the certificate or public key is associated or 'pinned' to the host. If more than one certificate or public key is acceptable, then the program holds a pinset (taking from Jon Larimer and Kenny Root Google I/O talk). In this case, the advertised identity must match one of the elements in the pinset.

OAUTH2

The OAuth 2.0 authorization framework enables a third-party
application to obtain limited access to an HTTP service, either on
behalf of a resource owner by orchestrating an approval interaction
between the resource owner and the HTTP service, or by allowing the
third-party application to obtain access on its own behalf. This
specification replaces and obsoletes the OAuth 1.0 protocol described
in RFC 5849.

Disclaimer: I work at Approov.

Securing Mobile Connections - Storing secrets and keys

You have done a good job of identifying that handling the key is in fact the hard part.

There is one error, it is possible to have a system that never exposes the keys and that is what the banking industry does. That is because the encryption/decryption is done at each stage by hardware. The hardware has the key internally in such a way that it can not be extracted from the device. One simple example are smart cards as found in cell phones and credit/debit cards in Europe. Another is in HSMs (hardware security modules) used by banks and other financial entities in the communications chain. Even the PIN pads on ATMs perform the encryption in hardware in the keypad itself. I mention all this because you state the application is involved in monetary transactions.

If the client is an iOS device you can store the key in the keychain, it is a cryptographically secure part of the hardware that is a TPM (Trusted Platform Module) equivalent. It is protected by the PIN the device PIN, note that the PIN can be set to have more than the default four digits. On-device attacks, even on jail broken phones, must use the keychain and attempts have a minimum time per attempt (by design) thus ensuring a minimum average attack time based on the PIN complexity. Off the device the only attack available is brute force which is infeasible.

The weak point is that the key will be in the clear during encryption and decryption. If the key is ever in a Foundation object (ex: NSString/NSData) there is a potential that it will survive after it's use, it is best to stay with "c" char arrays and clear them after use.

OK, the practical solution: Hire a crypto domain expert if you really want security. At a minimum hire one to advise and vet the design and implementation, I do. Look for someone with a CISSP certification and experience in the area of encryption. The CISSP requires a minimum of five years working 100% in the field under direct supervision, a six hour test and generally about 160 hours of test study time and 40 hours of continuing education per year.

How to securely include secret key/signature in iOS/Cocoa apps

I'm afraid it's not possible to do that. But as far as I know apple will make sure no other app is spoofing your app's secret. If it's a jailbroken phone, then the user is in a way taking full responsibility, and possible damage should be limited only to the jailbroken phone user's data.

Store an encryption key in Keychain while application installation process

The way you solve the sniffing problem is that you communicate over HTTPS for your web service. NSURLConnection will do this easily, and all web service engines I know of handle HTTPS without trouble. This will get rid of many of your problems right away.

On which machine is the 100-1000x decrypt the bottleneck? Is your server so busy that it can't do an asym decryption? You should be doing this so infrequently on the phone that it should be irrelevant. I'm not saying asym is the answer here; only that its performance overhead shouldn't be the issue for securing a single string, decrypted once.

Your service requires SMS such that all users must provide their phone number? Are you trying to automate grabbing the phone number, or do you let the user enter it themselves? Automatically grabbing the phone number through the private APIs (or the non-private but undocumented configuration data) and sending that to a server is likely to run afoul of terms of service. This is a specific use-case Apple wants to protect the user from. You definitely need to be very clear in your UI that you are doing this and get explicit user permission.

Personally I'd authenticate as follows:

  • Server sends challenge byte
  • Client sends UUID, date, and hash(UUID+challenge+userPassword+obfuscationKey+date).
  • Server calculates same, makes sure date is in legal range (30-60s is good) and validates.
  • At this point I generally have the server generate a long, sparse, random session id which the client may use for the remainder of this "session" (anywhere from the next few minutes to the next year) rather than re-authenticating in every message.

ObfuscationKey is a secret key you hardcode into your program and server to make it harder for third parties to create bogus clients. It is not possible, period, not possible, to securely ensure that only your client can talk to your server. The obfuscationKey helps, however, especially on iPhone where reverse engineering is more difficult. Using UUID also helps because it is much less known to third-parties than phone number.

Note "userPassword" in there. The user should authenticate using something only the user knows. Neither the UUID nor the phone number is such a thing.

The system above, plus HTTPS, should be straightforward to implement (I've done it many times in many languages), have good performance, and be secure to an appropriate level for a broad range of "appropriate."



Related Topics



Leave a reply



Submit