I have an app where users create accounts by username and password. However, I also want users to be able to add friends via their mobile #. Is there a security reason as to why I would need to verify their number if my design goes as follows:
User A enters her # into app, which saves to database
User B gives app access to his contacts. User A is a contact in User B's address book. When the database is queried for all #'s in User B's contacts book, we find User A's # and User A is returned.
How could there be a security flaw if User A entered a false #?
That would definitely cause security issues. Of course, for an app like this, you would need some way to verify the data that you are receiving. What if one if the contacts phone numbers are wrong? Some phone numbers change all the time now and it would be difficult keeping up to date with them all.
But on a bigger note than that, I don't think this one would fly with Apple. I've never designed an app that needed to access more than one contact at a time and the user was fully aware of which contact he/she was importing to a database. But for an app to automatically upload multiple contacts from a users address book for intent to be stored on a remote database might cause security flags to be raised at Apple during the review process. So the app may never see light of day on the Apple Store.
If you really want to implement something similar, make sure users verify their phone number before use and instead of storing the users contacts on a server, just store the verified phone number. Then you can use the contacts in your phone to check mobile numbers that have been verified of other users and which ones have an account linked to them.
Related
I am building a native social app in Android and iOS
I am using contacts from users phonebook to determine if his target friends are on our app or not and send the events accordingly
I recently came across this news that Apple is banning apps to send contacts to the server, which is the backbone of my app in order to function
How should I approach this problem? How do apps like WhatsApp which sync contacts (whole phonebook) to their server manage through this?
Do I need apple review of the app to access phonebook permission?
From This article I quote
But the phone maker didn’t publicly mention updated App Store Review
Guidelines that now bar developers from making databases of address
book information they gather from iPhone users. Sharing and selling
that database with third parties is also now forbidden. And an app
can’t get a user’s contact list, say it’s being used for one thing,
and then use it for something else -- unless the developer gets
consent again. Anyone caught breaking the rules may be banned.
Since the question is quite general let's dive into it a bit.
Looking into the App Store Review Guidelines there are three places mentioning that users' contacts should not be collected.
First and second, users should not be forced to provide their address book in exchange for app functionality (paying with contacts; highlights were added, a similar phrase is used for app subscriptions):
Apps should allow a user to get what they’ve paid for without performing additional tasks, such as posting on social media, uploading contacts, […]
Third, uploading and/or storing contacts to/on a server has an impact on users' privacy and is prohibited for the following use-cases:
Do not use information from Contacts, Photos, or other APIs that access user data to build a contact database for your own use or for sale/distribution to third parties, and don’t collect information about which other apps are installed on a user’s device for the purposes of analytics or advertising/marketing.
This does not exclude using contacts for creating a social graph for the benefit of your users. However, collecting all contacts might violate the principle of data minimization. So Instead of just uploading all contacts, Apple recommends to use a contact picker (see ContactsUI), where the app only gets access to the contacts the user selected:
Data Minimization: Apps should only request access to data relevant to the core functionality of the app and should only collect and use data that is required to accomplish the relevant task. Where possible, use the out-of-process picker or a share sheet rather than requesting full access to protected resources like Photos or Contacts.
The Art. 32 of the GDPR requires you to take the
[…] the state of the art, the costs of implementation and the nature, scope, context and purposes of processing […]
into account.
I think that the process has to be made transparent (as in comprehensibly explained to the user):
The user should have control over which contacts are used for discovery. All would be a valid choice – selected contacts (through the contact picker) or manually entering contact information (phone number, email – whatever is used for your contact discovery process) would be valid choices as well.
The app should function even if the user denies access to the contacts. In that case you can still offer a contact picker, or manual entering.
You must describe the process, including what information is used and for what purpose, in your privacy policy.
You should at least hash the processed values, as you do not need the actual phone numbers or email addresses for contact discovery and hashing comes without much effort and cost. However, be aware that hashing of personally identifiable information is not sufficient for "anonymising" these values – which is a common misconception.
For more advanced protection, you can take a look at the blog post by the authors of the Signal app, where they describe technical details on how they protect their contact discovery process.
I want to let users of my iPhone app invite people from their contacts to a group they're creating. I can use deeplinks for people that already have the app installed to have an invitation automatically show up, but I was wondering if I can somehow pass custom information to someone downloading the app for the first time so after they initially open the app they'll have an invite waiting.
As far as I can tell this is impossible but I was wondering if there's any other way to somehow associate a contact with that person making an account on their own device. My application uses gmail authentication for account creation so if everybody had each other's gmails saved in their contact this might be possible, but that's not the case unfortunately. If I could get a user's phone number then it would be easy but I know that's not allowed without specifically asking the user.
Does anybody know if it's possible to do something like deeplinking for people installing the app for the first time?
You can do this with Google Firebase Dynamic Links. Google has a guide for this here:
https://firebase.google.com/docs/dynamic-links/
If I understand the question correctly, here is what I'd do:
Scenario: Send Invite
If the email invited by a user is a registered email, done.
If the email invited by user is not a registered email, store it in a separate table (pending invites)
Scenario: Sign up/ Sign in
User registers using email, store user information.
When the user logs in, check if email exists in pending invites table, if exists, present invitation.
Delete user from pending invites table
Not sure if you have it already but you might need a db table to keep the invitations sent by your users.
What you're describing is called Deferred Deep Linking (Deep Linking refers to using a link to open your app directly to a specific piece of content, and Deferred means that it works even if the app isn't installed first).
As you noted, there's no native way to accomplish this on either iOS or Android. URL schemes don't work, because they always fail with an error if the app isn't installed. Apple's newer Universal Links in iOS 9+ get closer in that they at least don't trigger an error if the app isn't installed, but you'd still have to handle redirecting the user from your website to the App Store. You can't pass context through to the app after install with Universal Links, so you wouldn't be able to present the invitation. Additionally. Universal Links actually aren't supported in a lot of places.
To make this work, you need a remote server to close the loop. You can build this yourself, but you really shouldn't for a lot of reasons (not the least of which being you have more important things to do). Free services like Branch.io (full disclosure: Branch is so awesome I work there) and Firebase Dynamic Links are designed to solve exactly this requirement, and can handle all of the backend infrastructure for deferred deep linking so you don't have to. From your perspective, as the developer, you'll seamlessly get exactly the same data to work with whether or not the app was installed when the link was clicked.
I'm developing an iOS application in which users can buy an extra feature through an in app purchase. I have gotten the in app purchasing and restoring the purchases working correctly, where I save a boolean to the NSUserDefaults saying whether they have successfully bought and or restored the purchase.
However there is a bug where if User 1 buys the in app purchase on their phone, then logs into the App Store on User 2's phone and restores purchases. Then logs out again and allows User 2 to log back in, it means User 2 still has that in app purchase unlocked for free as the boolean in NSUserDefaults is still set to true.
I'm trying to find a way to query the user's App Store email or another way to check if the user's App Store email is the same as the one they bought the purchase under. But this needs to be done locally as the user could use this feature when they don't have any internet connection.
Does anyone have any suggestions of how I can do this or any better practices?
Thanks
This is, unfortunately by design, so as the old adage goes "it's not a bug, it's a feature".
It's designed like this so a user with multiple devices (e.g. iPhone and iPad), can make a purchase on the first device and benefit by restoring their purchases on their other device(s).
Of course this opens the door for people to share purchases across other peoples devices just as you describe.
The good news is there is a property on SKPayment called applicationUsername, its purpose as the docs state...
Use this property to help the store detect irregular activity. For example, in a game, it would be unusual for dozens of different iTunes Store accounts to make purchases on behalf of the same in-game character.
If you don't have anything unique to identify the user, e.g. an email, username, id, etc then your problem can't be solved I'm sorry, but if you do, keep reading, this is where it gets interesting.
When the user restores their purchase you should use the restoreCompletedTransactionsWithApplicationUsername method to make the call instead of restoreCompletedTransactions.
The docs are unclear what happens next, but my understanding is transaction state will be SKPaymentTransactionStateFailed if the username sent in the purchase call is not the same as the username sent in the restore call.
But if i'm wrong then you should be able to find the applicationUsername on the payment property of the transaction and compare it yourself before setting your property on NSUserDefaults. Sorry I haven't tried this myself, I only know the theory.
When setting the username, don't set it as plain text, the docs on applicationUsername suggest that...
The recommended implementation is to use a one-way hash of the user's account name to calculate the value for this property.
And further in Detecting Irregular Activity they explain...
Don't use the Apple ID for your developer account, the user's Apple ID, or the user's unhashed account name on your server.
Also, ideally you will be using a constant identifier, i.e. something that can't be changed for the user. If you use a hash of their email address for instance, if they change it and you didn't keep that hash as a constant restoring will fail as an unintended side effect.
Hope this helps.
You can control it via your servers by checking originalTransactionIdentifier of the receipts. As this remains same for all the purchased from one itunes account. You can associate this originalTransactionIdentifier with the username. Next time if you receive some already stored originalTransactionIdentifier against a different username, you can take the actions according to your suitability.
In an iOS application, When I detect a users improper action (for example posting violent content), I wan't to suspend the user from using my application. The basic idea to implement this feature is to create and save an unique id for each application installs and suspend the usage from server api's.
My question is, how can I implement this feature even if the user re-installs the application, and still pass the Apple's iTunes submission?
I came up with two ways to technically implement this feature, but wondering how Apple would respond.
Store the IDFA (I understand that users can reset the id on their behalf)
Store an app generated udid to the Keychain (which should not be deleted even if the user deletes the app)
I know there are no perfect answers, but would appreciate to discuss this issue with anyone that have tried submitting a similar application, or anyone that is well aware of the Apple's guidelines. Thank you.
Apple will reject apps that inappropriately use the IDFA.
If your app does not use server login (at which point, whatever flags you require could be delivered to the client), keychain storage would be the only real solution.
However, if you don't use server login, you block the device, not the user. Is this your intent?
BTW, without server login, a determined user can still get around keychain storage: Reset keychain on the device
You can block a given account. Most people these days key an account with an email address. Some require a credit card (Facebook fully validates accounts using credit card numbers), others require a bank account (PayPal has to send money somewhere!) and it is growing in popularity to request a phone number (Twitter is getting there). In the end, to really be effective, you have to block something that is difficult to produce.
With email, your users can always create a new account. Check out mailinator.com. Alternatively, all you need is one domain to have as many email addresses as you want -- I use five different email accounts daily, and I use about two dozen more on a monthly basis.
Installation ids are ok but users can always just uninstall/reinstall. And if you do manage to get a device-identifying number (easy to do really, even in the post-UDID era) so that you can block a given device, your users can just get a new device, or hack your app to use some random value, or spoof your API with cURL. I own three iPhones, two iPads, two Samsung tabs, three other Android phones, two Mac Book Pros, a mini, two PCs, and I run three virtual Linux boxes, and one virtual XP box. And what happens when somebody sells a blocked device to a non-abusive user?
So just block the user's account, keep excellent log files, and keep fighting the good fight.
According to this CloudKit overview:
CloudKit also enables your users to anonymously sign in to your apps with their iCloud Apple IDs without sharing their personal information.
I can't find anything else in their documentation about this capability. I already have an app with my own backend, so I wouldn't need any of the back-end-as-a-service features that CloudKit offers, but I would like to take advantage of logging a user in with their iCloud account, much the same way we currently do with Facebook and Twitter.
Is that possible with CloudKit, or do you also have to leverage their BAAS features in order to take advantage of login?
From what they discussed at WWDC, you'd do this using the fetchUserRecordIDWithCompletionHandler: method on CKContainer. That returns a CKRecordID that corresponds to the current user. This ID will be stable across devices but different for each app-- so if the same person uses your app on multiple devices, your app will get the same result everywhere, but other apps would get different results from yours.
Once you have the CKRecordID you can look up limited other user data (their name and email, I think) using fetchRecordWithID:completionHandler:. This request will trigger a permission alert to the user, so you only get it if they allow it.
This doesn't require you to use anything else in CloudKit. It does require that the user actually have an iCloud account configured on the device.
The permission alert will only pop if you call -[CKContainer requestApplicationPermission:CKApplicationPermissionUserDiscoverability...].
If the user grants permission (CKApplicationPermissionStatusGranted) then you can get the user's first and last name by running a CKDiscoverUserInfosOperation.
Requesting discoverability means that you can see the user's first and last name, and that any other user of the container can find their user record ID via an email address or look up their first and last name via a user record ID.