Unique id for identifying devices even after clearing app data [duplicate] - ios

This question already has an answer here:
Getting two different device IDs from same iphone
(1 answer)
Closed 5 years ago.
The backend apis I am using take unique device identifier and generate responses. In the client side, I am generating UUID for this unique identifier since Apple does not allow getting IMEI. I am storing the UUID (UserDefaults storage) and fetching it every time an api call is to be made. Now, my problem is that if the user clears the app data, the stored UUID gets cleared and a new id has to be generated. However, with this new id, the user request becomes invalid. How can this issue be resolved? Is there some kind of id that remains constant for a single device (something like device id in android)?

you can use the keychain secure storage to store the UUID, This will keep persisted even if you uninstall and then install the app.
Here is the 3rd party library written in Swift which simplifies the use of keychain.
https://github.com/evgenyneu/keychain-swift
By #Anand (Pls see the first comment).
Keychain is the actually good choice for storing UUID of the app in a secure manner, that can be persisted even when the app is deleted and re-installed. But in case, if the user resets the device for clearing the app data, even the keychain data will be deleted.

Related

Does iCloud silently copy Core Data persistent store files from device to device? non-unique NSManagedObjectId?

I've got an app which uses a proprietary method of syncing data from the app to the server and back out to any other app that user is using (iOS and Android).
I'm not using iCloud syncing and I don't want to use iCloud Core Data syncing, so I just want to make it clear that I'm NOT trying to do that.
When the app is uploading a new record to be created on the server, it sends up the URIRepresentation of NSManagedObect.objectID which the documentation says is A compact, universal identifier for a managed object, so that the server can detect if it has already seen this record before (perhaps the app already tried to upload this data, but something failed later on in the process, so this helps us avoid creating duplicate records on the server).
Here is an example of the object id: x-coredata://80978028-AEB5-45F0-AAD5-F328C4B294AF/MedicineShot/p1481
According to the documentation, this object id is supposed to be unique for my app... but I can't really tell what the scope of the uniqueness is, for example, if one person has my app on an iPhone and an iPad, will it generate the same object id in those two different stores on two different devices?
We've been running this app/server for 6 years and we've never had an id conflict, that we know of, but we appear to have run into one.
A user created a record on their iPhone with the above example coredata id. That same user, 5 days later, created a new record on their iPad and it has the exact same coredata id. Since our sync server uses that id to determine if it is receiving a request to create a record that it has already created, the server treated these two different records as the same.
We've never seen this before and the documentation seems to say that this shouldn't happen because these ids should be unique. The Managed Object Id is supposed to be a universal id for a managed object, but these are two different devices creating two different records on two different days (5 days apart)... with the same id.
It was the same user, who is probably using the same Apple Account on both devices.
Could iCloud be secretly copying the persistent store files from one device to another?
If so, is there a way we can prevent iCloud from copying those persistent data store files so that we can ensure we're getting unique ids from device to device?
EDIT: The object id uri has what appears to be a UUID of 80978028-AEB5-45F0-AAD5-F328C4B294AF and UUIDs are supposed to be Universally Unique as the name says. Is that part of the object id a UUID? If so, how can the Core Data persistent store on two different devices produce the same object id uri?
Despite what the documentation suggests, managed object IDs are only unique within a specific persistent store file. They're not guaranteed to be unique everywhere. I know, I've read the docs too, and I know they say "universal"-- but I think it's also important to note that they say
Identifiers contain the information needed to exactly describe an object in a persistent store...
But they don't say anything about multiple persistent stores. Core Data was originally created for use within an app, and the docs have not always kept up with the idea of syncing to servers or other devices.
The form of the URI-- x-coredata://80978028-AEB5-45F0-AAD5-F328C4B294AF/MedicineShot/p1481-- is undocumented, but the parts are:
UUID: An identifier for a specific persistent store. This is also saved in the persistent store's metadata, so that instances and stores can be matched.
MedicineShot: The entity used for this instance
p1481: p implies "permanent" (temporary IDs have a t and a different format), and 1481 is basically an incrementing primary key within the persistent store. It starts at 0 and counts up every time you insert a new instance of the entity.
Using a managed object ID from one store in another store is unlikely to work well. Apart from the UUID, the unique IDs won't match unless you're very careful to always insert new instances in the same order.

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.

Using an Encrypted Realm in a background or notification processes?

Realm has a great write up and sample code for encrypting your database. This documentation and sample work as intended, until you try to decrypt realm when:
A user has a password on their phone
The device is locked
Your app is trying to do work with Realm when a remote notification comes in
This happens because we can't access the keychain to get (or create) the key to en/decrypt the Realm. The default kSecAttrAccessible value is kSecAttrAccessibleWhenUnlocked
There are a few options as I see them:
Change kSecAttrAccessible to kSecAttrAccessibleAlways. I don't like this because it's a) too open and b) it was slated to be deprecated in iOS 9
Change kSecAttrAccessible to kSecAttrAccessibleAfterFirstUnlock or kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly. This is better but still feels too open to me, even though the docs state: This is recommended for items that need to be accessed by background applications
Create a second, non-encrypted Realm to use as a staging database. Store notification data here, then when the app wakes up from user interaction (the device would be unlocked), move the data from the staging Realm into the encrypted real one. This doesn't feel right either, as we'll have data temporarily not encrypted
Combine 2 and 3 and encrypt the staging Realm, and protect it's key with kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly
??
I'm currently trying to decide if #2, if #3 is worth putting the time into, or if I can come up with a #5
Is there an approach here that I clearly should use or one I've missed?
Thanks
I'm an author of KeychainAccess library. I strong recommend you to use kSecAttrAccessibleAfterFirstUnlock (The 2nd option). It is the best way to access keychain items from the background.

Losing access to the keys stored on iOS Key Chain

We have an app on the iPhone App Store which needs to store the user id and password on the device for features like Touch ID and Remember Me.
Both user id and password are encrypted and the respective AES key is stored in the device key chain.
Now, the problem statement is : we are unable to retrieve the AES key from key chain every time we update the app from AppStore and also when user updates iOS on their device (eg : from iOS 9.1 to 9.2).
Since we are unable to retrieve the key, we are unable to decrypt the user id and password that results in failing a couple of key features every time user updates the app (eg : Remember Me and Touch ID).
This is becoming a huge concern since the issue continues until user totally uninstalls and reinstalls the app.. When user reinstalls the app, every thing works fine. We can enable Remember Me, Touch ID features and they are enabled fine and works fine.
What must be going wrong ?
In general keys in the keychain persist across update and even deletion and re-installs. So, there is something you are doing that is not correct. Please provide more information.
It is not necessary to encrypt the name and password, they can be stored directly in the keychain, the keychain encrypts it's contents.
Are you changing the Bundle ID when you update? If so have you made the keychain available to a group all the updates belong to?

How to uniquely identify users ios7+?

I want to know who the user is without them actually logging in. There are bunch of methods on the internet and the one I am currently using is:
static let DeviceId = UIDevice.currentDevice().identifierForVendor.UUIDString
The problem is this resets when the user deletes and reinstalls my app. Also somehow this value changes in about 1-5% of the users without them actually deleting the app. It happens after they upgraded to a new iOS version. Possibly happens when they change appstore country too.
I want the user id to be unique no matter whatever the user does. Kind of like how Whisper app works.
What is the best way to do this? Advertising identifier looks really good on paper, but does apple allow using that just for user login info?
Should I use keychain? icloud? Is there some other value I can use?
Here are some sources I read about this topc:
http://tinymission.com/post/ios-identifierforvendor-frequently-changing
http://possiblemobile.com/2013/04/unique-identifiers/
How to preserve identifierForVendor in ios after uninstalling ios app on device?

Resources