Security of Firebase API Keys in Xcode Plist files [duplicate] - ios

This question already has answers here:
Is it safe to expose Firebase apiKey to the public?
(10 answers)
Closed 1 year ago.
So I watched this video Youtube Tutorial
In this video, it is recommended NOT to include API keys in xcode plist files. So Firebase generates a plist file for us to include in our projects and in that plist file is the API key. Is there a way to do this without using the plist file so that it is more secure?

Your app's public API keys are not (and should not be regarded as) secret(s) as they are needed in order for your app to identify itself to the Firebase backend.
Even if you were to store them elsewhere, they could be extracted by other means by a malicious actor.
Because the API key is the same for every single instance of the app, it would only take one bad actor to discover and disclose it.
Firebase themselves likely have intelligent abuse detection so you should not need to worry too much about DoS attacks or any other possible attack that involves your API key.
However, some "abuses" of your app simply aren't possible to prevent if you have a public-facing app anyway.
It depends on what your app does and what you would consider to be "abusive" behaviour.
Trying to obfuscate your API keys will only create more friction for you as a developer and will not win you much in terms of security.
You should focus security efforts on other parts of your app.
Important: I'm talking about public API keys, not private keys such as Firebase service credentials.
These really are private and you shouldn't ever include them in your app (only store them on your server).

Related

Firebase GoogleService-Info.plist file stolen

My GoogleService-Info.plist file for iOS was stolen, is it possible to disable access to my Firebase Firestore to all current iOS devices, and reset this file ?
I tried to delete my iOS app in Firebase, but I can still make request from my iPhone...
And I need to disable access only for iOS devices not Android.
As Doug Stevenson pointed out the contents of the GoogleService-Info.plist are public and accessible to every iOS user of your application. Therefore it is inaccurate to say they could be stolen as they're already publicly available.
As explained in the Firebase documentation the file fields contain identifiers used by your application and Firebase servers to route the requests being made to Firestore, Real Time Database and the rest of products the app might be using. Reading the documentation or the post shared by Doug you would see the information exposed is not a security threat.
Moreover, I would like to point out that everybody could try to access your Firestore collections and try to add/drop data. This is indeed expected as Firestore is publicly accessible by mobile and web clients. However, this doesn't mean Firestore is exposed to users to do whatever they please, instead, the actual access is totally under your control by the means of security rules, which enforce what actions a given user could do. In that sense, the developers who left will only have the access level that your security rules grant them, which shouldn't be a threat when having good rules in place.
Lastly, you may revoke the credentials completely removing the application. I'd say it's not a great idea as you would cause a service disruption to app users. Also, this won't improve security or diminish risks.
You can remove the app directly from the Firebase console
Before proceeding make sure to check and understand the consequences.
Click on Settings > General;
Scroll down to Your Apps;
Identify the app and click on Remove this app.

Invalid binary when uploading to App Store

I was using the following features before, I am not using it at the moment, so I removed it from info.plist, but I am having a problem when I upload the application. I don't want to add those features to info.plist because I don't use them anymore. What should I do?
ITMS-90683: Missing Purpose String in Info.plist - Your app's code references one or more APIs that access sensitive user data. The app's Info.plist file should contain a NSPhotoLibraryUsageDescription key with a user-facing purpose string explaining clearly and completely why your app needs the data. Starting Spring 2019, all apps submitted to the App Store that access user data are required to include a purpose string. If you're using external libraries or SDKs, they may reference APIs that require a purpose string. While your app might not use these APIs, a purpose string is still required. You can contact the developer of the library or SDK and request they release a version of their code that doesn't contain the APIs. Learn more (https://developer.apple.com/documentation/uikit/core_app/protecting_the_user_s_privacy).
ITMS-90683: Missing Purpose String in Info.plist - Your app's code references one or more APIs that access sensitive user data. The app's Info.plist file should contain a NSCameraUsageDescription key with a user-facing purpose string explaining clearly and completely why your app needs the data. Starting Spring 2019, all apps submitted to the App Store that access user data are required to include a purpose string. If you're using external libraries or SDKs, they may reference APIs that require a purpose string. While your app might not use these APIs, a purpose string is still required. You can contact the developer of the library or SDK and request they release a version of their code that doesn't contain the APIs.
If you're seeing that warning, the App Store (by automatically looking through your compiled application) believes that you're using those features. Usually this means that code exists in your application that references these APIs. In this case, it's code that works with the camera and photo library. Even if you don't use those features any more, if the code in your compiled binary references those APIs, Apple will insist on those purposes being present in your info.plist (since they can't tell the difference between those features being present and used, or present and unused).
Your choices are:
If you don't think those features will be coming back, remove the code that uses these APIs entirely from your app. You may also want to just temporarily not include the files by removing them from your app's build target.
If this is too complex, and you're certain that these features aren't actually in use in your app any more, then fill out those parts of your info.plist with whatever messages you had previously, safe in the knowledge that no user will ever actually see them.
In summary, if you reference those APIs, even if you don't use them, you must have appropriate purpose strings in your app's info.plist.

how can I keep my api keys safe on React Native App

I'm building a Native app with React Native. I was once a web programmer and it's my first time using React Native and making native app especially which is going to be actual product and serve for normal users. During my struggle, I've encountered some issue that I, as a former web programmer, can't find a way out.
In my app, I call some APIs that any other app would/could be using, like Google Maps via react-native-maps library. My API keys are saved at files that are used when actually build the app, info.plist and AppDelegate.m ( building iOS app first by now ). I've thought that would be safe enough. But I recently find out it might not.
After reading some articles about getting rid of secret informations from native apps, I've tried hard to find a way out. Thought about using .env, getting api keys from backend server, etc. couldn't use .env, and can't find a way to call API, sending API keys ( not containing them as a build meta data ).
So here's my question. How can I keep my secrets safe for react native app?
I guess it depends on what kind of secret and API we are talking about.
With Google Maps is it possible to restrict usage to specific apps or domains which makes it safe to bundle the key in the app, read more here: https://developers.google.com/maps/api-key-best-practices#application_restriction
In situations where the app itself does not need the make the request itself, an alternative would be to let the server make the request and forward the result to the app.
In other situations where nothing from above works, you could send the secret from your server to an authorized user. Be aware that the user could then read the key but at least you don't need to bundle the key into the apps which also makes it possible replace the key if needed.

How to store critically sensitive information such as secret, key, token, encryptionKey in iOS application

When we talk about securing iOS application we often forget to secure most critically sensitive information such as secret, key, token, encryptionKey. This information is stored in iOS binary. So none of your server side security protocol will help you.
There are lots of suggestion that we should not store such information in the app but store in the server and get it via SSL secured web service call. But this is not possible for all application. E.g. if my application does not need web service at all.
In iOS app we have following option to store information.
UserDefault: Not appropriate for this case
String Constant: Not appropriate for this case. Can be reverse
engineer to retrieve or just use strings command
Secure Database: Store in Secure and encrypted Database. But again have responsibility to secure database username and password.
KeyChain: Best to store critical info. But we cannot save information before installing the app. To store in the keychain, we first need to open the app, read from some source and store in the keychain. Not appropriate for our case either.
Custom Hash String Constant: Not to directly use secret, token, key from service provider (mixpanel, paypal), instead use hash version of that information from custom key. This is also not perfect solution. But add complexity during hacking.
Kindly send some awsome solution to this problem.
If you don't want to use your own backend then use Apple. You can configure On Demand Resources and keep data file with your key, token, any secret on Apple server. After first download you can write this data to Keychain which is secure enough. I'm guessing networking between iOS and Apple server is also secure enough.
On-Demand Resources Essentials
Accessing and Downloading On-Demand Resources
1) Internet Connection Required
1.1) Push Notifications
Great way to have a secure data exchange could be to use (silent) push services from Apple, those use the apns and send data through https - more Details 3.1
1.2)
A more or less similar approach is also used when distributing new user certificates to already deployed applications, if a reinstall of the application is no opportunity AND the application requires a working internet connection anyway.
Downside: working network connection required and basically the information is coming to the application, when it is already being executed => seems not to be appropriate for your case. (see step 4)
2) Static data (as there will be no exchange without network connection / communication partner)
Encryption of data with private key being provided in the bundle itself. Whether it is now a string or a hash, which can be reverse engineered with functions you got emebedded in your application.
Since iOS9 it is pretty hard to decompile iOS applications and basically you will mainly have a look into the provided header-files. So if you had such a function, string, hash value or whatever, make sure you got it in your .m-file!
But again: if the information is not device or user specific, just a secret across your own micro environment, valid across all devices, you would have to provide the encrypted data AND the decryption method in the same bundle, if there is no update process / information exchange or something else, you can think of.
Good for encryption:
iOS System.Security https://developer.apple.com/reference/security
or simply openssl
The difference between your described keychain approach is:
You got a value, which WILL be encrypted and stored securely.
(2) describes the approach to have an encrypted and stored (in bundle) semi secure value, which WILL be decrypted
3) Information exchange
You describe critical data, which was hashed by another instance. Great! - Make sure, relly make sure, the instance you are talking to is really the instance you expect to be (Network Hooking prevention with ssl certificate pinning etc, but even here you might have intruder (men-in-the-middle)). And you will (probably) have a certificate being provided in your application bundle, to ensure the authenticity of the communication server - here you go again, data that is supposed to ensure a secure process between certain instances of your micro environment. Nevertheless, this data is being provided in your application's bundle.
3.1 Secure Information Exchange extended - Silent Push
Make use of Apple's servers to exchange your secrets for this purpose. If you just need to exchange small data chunks. I would recommend to use silent push notifications to the user, those do even work without explicit permission from the user. Huge advantage: In case your secrets or keys change, you can inform users as soon as possible about the change. They will likely only need the change, when they receive new data, which should reliably work in most cases. Exception: Data exchange in local networks or via bluetooth, in this case I would recommend to provide a notification to the user to have the requirement to update a local decryption key. Or exchange the key in this format as well. Once again: I am leaking some detailed information about your environment architecture.
Downside: You don't know, whether a user just used your app for the first time, until the user "tells" you so.
https://developer.apple.com/library/content/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/APNSOverview.html#//apple_ref/doc/uid/TP40008194-CH8-SW1
3.1 Secure Information Exchange extended - In App Purchase
Use a frree In-App Purchase for the user to get the data to your phone. Good point here: you can provide larger data chunks easily, as this should be an active request by the user, the user does expect certain processing time and should also be aware of the fact to require a working internet connection.
Downside: User would have to select this on purpose. Up until then the app would not work accordinly.
https://developer.apple.com/library/content/documentation/NetworkingInternet/Conceptual/StoreKitGuide/Introduction.html#//apple_ref/doc/uid/TP40008267
So, it just slightly differs from the approach (2) in its basic idea.
In short: Can you provide additional information, what kind of data you need to encrypt/want to store securely and whether you will have a network exchange or not?
Would need some more information here :-)
I would like to emphasize once again that an application on iOS is not that easy to decrypt anymore, even decompiling would not get everything, you expect it to get. For instance decryption tools like dumpdecrypt were only working properly up until iOS 8.4
It seems to me that the best way to do this is using the built in CloudKit. You can save your secrets in the CloudKit Dashboard and then fetch them on startup. Since CloudKit is only a transport layer you'll have to store the app secrets in the KeyChain.
I know you mentioned the KeyChain not being ideal for your use case (not sure why), but this is a good way of not including the secrets in your app. You can't get around fetching your app secrets from another source.
CloudKit access is secured using the system iCloud account and if there is no iCloud account you still access the iCloud servers securely. Another added benefit of this is that you can change your app secrets at any time, so if you want to be even more secure you can implement a rotation schedule.
Learn more about CloudKit
Cocoapods-keys might be a best option.
From cocoapods-keys doc's
Key names are stored in ~/.cocoapods/keys/ and key values in the OS X
keychain. When you run pod install or pod update, an Objective-C class
is created with scrambled versions of the keys, making it difficult to
just dump the contents of the decrypted binary and extract the keys.
At runtime, the keys are unscrambled for use in your app.
The generated Objective-C classes are stored in the Pods/CocoaPodsKeys
directory, so if you're checking in your Pods folder, just add
Pods/CocoaPodsKeys to your .gitignore file. CocoaPods-Keys supports
integration in Swift or Objective-C projects.
Check out this link for installation, usage and more info : https://github.com/orta/cocoapods-keys
I agree with #Lobsterman and believe that the best way will be to use a combination of these.
Don't include the secret information in the app initially.
Deliver the secret key either as in-App purchase content ,on-demand resource or send it through push notification. This will add the benefit of changing the key periodically if you want and the change will take effect without any additional effort.
Add the entry to keychain access once the content is delivered.
If the data is extremely sensitive then it should never be stored offline on device because all devices are crackable. If you still want to store on device then keychain is one option for storing data securely, However it's encryption is based on the pin code of the device. User's are not forced to set a pin, so in some situations the data may not even be encrypted. In addition the users pin code may be easily hacked.
A better solution is to use something like SQLCipher which is a fully encrypted SQLite database. The encryption key can be enforced by the application and separate from the user's pin code.

Privately sharing data between iOS apps that have different team IDs

How can I privately share data between two apps on the same device that have different team IDs? We used to do this via the pasteboard, but with iOS7 to use app-specific pasteboards they now have to have the same team id.
The problem we are trying to solve is the unlocking of features in one app if the user has purchased another app. We'd like this to happen quietly in the background (hence originally using app-specific pasteboards) but having some security to prevent users from spoofing the process and unlocking features.
One approach we are investigating is to use a system pasteboard but to encrypt the data with a device specific key. As long as both apps use the same algorithm to generate the key this should work, but he problem then becomes how to generate an app specific key.
Any advice/guidance on the best way of enabling this sort of feature unlocking scheme would be very helpful.
I use the pasteboard for sending data between applications as well. It's a really useful tool for sending medium size amounts of data between applications. I actually wrote up a blog post on the topic a while back.
Unfortunately, as you've pointed out, private pasteboards are only available to apps that share the same prefix in their app id. This is typically the Team ID, but may be different if you have an app that dates back to when you could use a different bundle seed identifier.
If you have medium sized amounts of private data being shared between apps with different prefixes then a different solution is in order. In this case I would suggest using some form of encryption and using the general pasteboard to shuttle the data around. Depending on the sensitivity of the data, it probably would be a good idea to encrypt the data even when using a private pasteboard. Rob Napier has a nice library for making the encryption and decryption very simple.
Alternatively, if your data is fairly small you might consider encoding the data into a URL and using a URL scheme to move the data into the other app.

Resources