Verify In-App Purchases with Firebase Realtime Database - firebase-realtime-database

I'm trying to integrate in-app purchases into my app using Firebase Realtime database to verify/save records for the purchases. The problem is when I try to verify a purchase from client to back end server (Cloud functions) to check whether the key/purchaseToken already exist. But since Realtime Database can't store paths that contain "." (dot), how can I store and verify this information?
I think I can strip the dots from the strings but I don't know if that's the right way to do it.
Source: https://developer.android.com/google/play/billing/security#verify

If you have a key that contains characters that are not allowed (such as a .), then I typically encoded that character either with something else (e.g. it is common to replace the . in an email address with a , in RTDB keys), or with a generic URL encoding.

Related

Xamarin IOS identifying device

I'm writing an application which will be used in an enterprise, no outsiders.
This application should fetch data from API response and display it.
Each user has his own device, Ipad and should see only the data he is the owner of.
Problem i'm facing is identifying the device/user, so that API responds with only the information the user is supposed to see.
brief example of how it should work:
App is opened -> get unique id -> attach ID to API call -> receive appropiate response -> display data
As i imagine this ID should be static and not made upon installation of the app or generated.
I've tried getting UDID, Serial, MAC,- no luck, they're deprecated. Only managed to get .IdentifierForVendor, which is unique not in the way that i need.
So here is my question, are there any other options left?
Like fetching appleID name,email or should i make unique deployments for everyone separately?
Or a Log-in screen?
You could create a GUID for every App instance. However, apart from that you will have a hard time doing what you want.
These ways of identifying a device have been deprecated to ensure Advertisers and other malicious Apps cannot fingerprint a device easily.
If you don't want too much hassle authenticating everyone, you could apply a simpler scheme such as using a pin code, QR code, NFC tag or whatever you prefer.
However, if someone were to steal one of these enterprise devices and it would contain any secret information I would rather rely on something more secure as username and password, or even better something multi-factor.
Unique id's will have to be set by deploying the app from MDM. For example:
https://docs.jamf.com/9.9/casper-suite/administrator-guide/In-House_Apps.html
How should the application accept those variables, i dont know. Maybe it modifies .plist when deploying.
Solution i did was enforcing device name from MDM, so that users are unable to change it - and using that as the unique identifier.

Why one should not call receipt validation endpoint directly

Apple provides an endpoint to validate receipts:
https://buy.itunes.apple.com/verifyReceipt and warns against calling the endpoint from the app
It is not possible to build a trusted connection between a user’s
device and the App Store directly because you don’t control either end
of that connection, and therefore can be susceptible to a
man-in-the-middle attack.
It is stated, that the safe way is to send the receipt to "my own" server firstly, then communicate with Apple endpoint from the own server.
Honestly, I do not understand how does it help to increase the level of security. Yes, I do not control the /verifyReceipt endpoint, but Apple hopefully does. And why
phone <-> my server <-> Apple server is better than phone <-> Apple server?
Could you elaborate on this from point of view of the hacker (or man-in-the-middle)? How would he tamper the receipt/response in the latter case and what makes it difficult for him in the former case?
It's relatively easy to change an app binary to alter a string within the app. If your binary contains a string "https://buy.itunes.apple.com/verifyReceipt" then an attacker can change the string to "https://example.com/verifyReceipt" (a server that's under their control) and have the server return the receipt JSON that makes it seem like a purchase was successful. This is an easy attack to automate, so you just run a binary through a script which replaces all instances of the Apple URL with another URL.
When you communicate with your own server to Apple you can be (relatively) sure that that connection is secure. There are also ways to secure the communication between the app and your server such as a certificate in the app binary with a public key, the private key on your server. (I'm not an expert at this part so the details about keys might not be 100% correct).
All this being said there are other ways an attacker can make it look like a purchase went through. They can search your app binary for common receipt parsing libraries and flip known booleans (e.g. a userCompletedPurchase boolean flag). These attacks are easily scriptable.
The best way to make sure that your app isn't attacked is to remove the low-hanging fruit and make it that much more difficult that the common scripts won't open your app to attack. One way to do that is to not verify receipts directly with Apple.
I think that the key part to the section from Apple documentation that you cited, but didn't include, was the sentence before.
Using your own server lets you design your app to recognize and trust
only your server, and lets you ensure that your server connects with
the App Store server.
In particular the first half of that sentence (emphasis mine). I see this as a bit of nudge from Apple that the app should be designed as such to "recognize and trust only your server".
In the simplest case (ie. minimal), one could use their server as a proxy to reach Apple's server. The server could simply pass Apple's payload back to the app, or maybe send some simple JSON like
{
success: true
}
Or maybe even it's something as lazy as just sending a 200 response.
Using MITM, it's easy to change the response as needed. So even though you are using your server, the only barrier at this point is the attacker would need to determine what a valid response looks from your server.
They may be able to figure it out by simply sending a bad receipt and then seeing the response. Or maybe a hacker will TOFFT and just make a purchase to get the valid response and then provide others so they can profit.
This is "one step" above going to Apple directly, because everyone knows what the Apple payload is. Thus if the app goes directly to Apple it's easier for someone to be able to run a MITM and replicate a valid receipt response.
Going back to what Apple wrote, they are encouraging you to have a design that is more robust to help mitigate potential fake purchases from occurring. This robustness is what protects you more.
This can take the form in many ways.
For example, perhaps your server sends back the response in an encrypted format. Or replies with a hash. Even better if your app relies on your server through the course of usage, so the server can act as the truth. Or maybe the app periodically "phones home" to get a config of privileges. There are numerous ways one can make it more difficult for a hacker.
Apple is leaving to you just how you determine that trust with your server is established. It is after all, your "money".
As an example, the latest game I've made is specially built to use the server as the truth. So all moves go through the server (game is simulated on the server). While someone could certainly modify the app, in the end the server should theoretically correct any badness introduced.
Note, that it still is possible that someone can bypass even more robust security measures.
You can validate the iOS receipt on the iOS device. But you cannot be sure that the receipt is actually valid. The user could have hacked the device to make you think the receipt is valid.
Your users can edit the executable code of your app, and they can edit the operating system. With common/shared APIs like Apple's purchasing system, there are publicly available tools a user can run on their own phone to avoid paying.
Your server, however, is controlled by you. Your customers do not have physical access to it. And therefore your server (hopefully!) cannot be hacked. This means your server can be trusted, unlike the device. When your server establishes an SSL connection to Apple's server, you know you really are talking to Apple's server. Not one that your user-installed to bypass in-app purchasing.
UPDATE
Let's say you have got your Receipt after a user purchased your consumable product. So now you want to validate it and you have two options:
1. Receipt validation locally(from a user device).
2. Receipt validation through your server.
Local validation:
When you receive the receipt, you then read the contents of the receipt file by passing it through the verifyReceipt endpoint from your app. And you will get a response include a readable JSON body from this endpoints. Based on this response you can validate the receipt and control user action.
And all this happened in your app[user device]. After publishing your app you can't modify your app(if you need) without another release. Also, the user has more control of their device than you.
Validation through your server:
After getting Receipt data you need to encode the data in Base64. Send this Base64-encoded data to your server.
On your server, create a JSON object with the receipt-data, password (if the receipt contains an auto-renewable subscription), and exclude-old-transactions keys detailed in requestBody. Submit this JSON object as the payload of an HTTP POST request. In the test environment, use https://sandbox.itunes.apple.com/verifyReceipt as the URL. In production, use https://buy.itunes.apple.com/verifyReceipt as the URL.
Now you will get a JSON object response from App Store's that contains the keys and values detailed in responseBody. According to the response, you can validate receipt and send a response to the app for further actions.
So, if the user buys something in your app you don't need to store the thing being purchased inside the app. You want to store it on a server, and that server only sends the purchased data to the device after it has verified the receipt with Apple's server.
And you have more control in your server than your app also you can change any mechanism about receipt validation at any time(don't need to update your app) and control your user from the server.
Hope you will get it. Now it depends on you which one you prefer for you.
I will try to put my understanding here as I am deeply involved in auto-renewable subscription workflows.
Why is that endpoint there? what is the purpose?
The purpose of that API is to verify the purchase that user made using your app. So why do you want to call that API from the mobile(phone). In that environment, you already know that user has made the purchase.
But if you want to call that API to decode the encoded receipt inside the app(to read important values), then consider the other recommended approach. That encoded receipt is PKCS7 encoded and Apple itself provide lib to decode that.
Hope this helps

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.

Is it possible to add external data to CloudKit?

I'm writing an iOS app that uses data collected from websites. A large amount of data is retrieved when parsing the content so it needs to come from a backend server where data can be collected and added to the database once rather than parsed on the device.
I've looked at BaaS frameworks like Parse and am considering using this, but I'd like to know if it is possible to add records to CloudKit externally from say a Linux server? I've looked everywhere and can't find anything other than adding records programmatically (from the app) or via the dashboard.
You could create an OSX app (no other platforms are supported yet) that is communicating to the same CloudKit container. But then that app also needs to be signed and submitted to the app store. You don't have to make it public, you just need to submit it.

How does snapchat do their friends functionality?

So I am trying to have users in my app find each other via their address book (a la Snapchat). How do I go about this?
I can have access to the user's address book so I would be able to associate each number with a user (I verify this via text for each user). Once I have all these users associated though, would I have to compare each phone number to my data base (Parse) in order to have a section of "Friends who have MyApp"? Otherwise, how can I grab an address book of X user and tell them which of his contacts have the App already installed?
Also, I have read in many places I should not upload their contacts info to my backend.
Help?
First thing that comes to my mind is to store each user's phone number as well. However, you might be right about not to upload their contacts to your server even though you do ask for confirmation that you're going to access their contact list.
I'll put forward another idea, how about storing their contact list as encrypted data? Thus, even you personally won't be able to reach any of the contact info. Use an irreversible encryption algorithm like sha512 and then store these phone numbers as encrypted strings. Each time a user requests if his/her contacts are exist in your database, encrypt each phone number locally and make a request if those strings exist in your DB. This implementation is really similar to common password storing techniques and I believe it is quite secure -and ethical.
Related: How can I compute a SHA-2 (ideally SHA 256 or SHA 512) hash in iOS?

Resources