VerificationController uses uniqueIdentifier - iphone

I am trying to patch this security breach that Apple has identified. Only, the sample code (VerificationController) they provide uses this line:
[UIDevice currentDevice].uniqueIdentifier
Which has been deprecated and has had apps rejected from the app store. Any idea if this is OK again? or what is happening here?

Apple has updated the sample code deleting lines where UDID had been used.
In-App Purchase Receipt Validation on iOS

UDID vs UUID
From what I understand, Apple does not want developers to have access to a UDID (unique device identifier) anymore as it is not within an app's sandbox.
Think of a situation where a user gets a new iOS device (with a different UDID). Just because there is a new device does not necessarily mean there is a new user. Also, if someone gets a device previously used by someone else, we do not want to assume that because we have the same device, the same user must be using it.
Apple recommends using a UUID (universally unique identifier) for your apps instead. The only reason Apple allowed you to use UDID before was because they had not implemented UUID yet or had not considered the situations above (to my understanding). UUID's are generated for the object you want to keep track of (e.g. a user).
Basically, Apple's mentality is that you should keep track of users (or other instances), not devices.
Generating a UUID
To generate a UUID, try the including the following as a class method:
+ (NSString *)GetUUID
{
CFUUIDRef uuidReference = CFUUIDCreate(kCFAllocatorDefault);
NSString *theUUID = [(NSString *)CFUUIDCreateString(kCFAllocatorDefault, uuidReference) autorelease];
CFRelease(uuidReference);
return theUUID;
}
For my experience, I've called this method in the init method and stored the resulting NSString as a property of the instance that was just created.

Where did you hear that apps were rejected because of using it? Maybe they were using it maliciously but it is a public API. Also, look at the note on the page you linked to.
Note: This listing uses the symbols kSecTrustInfoExtendedValidationKey and SecTrustCopyInfo, which are not public API. Your app is allowed to use them for this specific purpose.
If they are even willing to let you use private APIs for this purpose, I doubt they would care about a public one.

Apple's problem with the UDID was always that they consider it private information, and so they were rejecting apps that sent it to, say, a server, without asking permission first. If you're just using it locally, I don't think you'll have trouble.

Related

What is a long-term method I can use to uniquely identify an iOS device?

What is the best way to uniquely register an iOS Device, which won't be limited by future Apple restrictions?
My current approach to register an iOS device (basically to identify the device uniquely) is that I use the UDID of an iOS device to identify it and register it, and then after recognising it I perform the necessary actions.
The issue is that the UIDevice uniqueIdentifier property is deprecated. There are certain workarounds for that (as discussed in this question) which I'm aware of.
One possibility is to use the MAC address of an iOS device. However, I feel that Apple may restrict access to this information at some point in the future, as well.
Is there any other way (besides accessing the MAC address) to identify an iOS device, which we can rely on for the future?
Using Apple's preferred method of generating a CFUUIDRef is probably the better solution as I feel the MAC address may be removed in the future as well. If you use this and save it to your NSUserdefaults you will have it persist unless the user deletes the app. If you want to have a generated unique ID that you can share between apps or persist between installs you should look at using the UIPasteboard and saving your generated UID with a key that you share between apps.
//Create a unique id as a string
CFUUIDRef theUUID = CFUUIDCreate(NULL);
CFStringRef string = CFUUIDCreateString(NULL, theUUID);
//create a new pasteboard with a unique identifier
UIPasteboard *pasteboard = [UIPasteboard pasteboardWithName:#"youruniquestring" create:YES];
[pasteboard setPersistent:YES];
//save the unique identifier string that we created earlier
[pasteboard setString:((__bridge NSString*)string)];
//accessing it
UIPasteboard *pasteboard = [UIPasteboard pasteboardWithName:#"youruniquestring" create:NO];
NSLog([pasteboard string]);
I have written a brief tutorial here but its basically the lines above: http://www.roostersoftstudios.com/2012/03/26/a-way-to-share-data-between-apps-on-a-given-ios-device/
Unless your application is for managing my Apple devices, it is the wrong approach. As a user, I don't want you to know which device I'm using. I want you to recognize me, whatever the device I use. I want to be able to replace a defective device. Apple will restrict more and more the access to this information.
[edit] I can't see how a MAC address could work. My iOS devices can have multiple.
Another option is dynamically generating your own UUID.
CFUUIDRef uuid = CFUUIDCreate(NULL);
CFStringRef generatedUuidStr = CFUUIDCreateString(NULL, uuid);
CFRelease(uuid);
NSString* uuidStr = [(NSString*)generatedUuidStr autorelease];
You could persist this UUID in NSUserDefaults for install based uniqueness. If device based uniqueness is truly the most important thing (so that after an uninstall and reinstall the id persists) you'll need a mechanism to persist the ID on the device. I think you could look into using the Keychain in order to persist that ID which should persist beyond app uninstall. You can even use an access group when adding the UUID to the keychain so that you could have a suite of apps that use the same UUID.
See apple's security framework reference for more info on saving keychain items and retrieving them.
http://developer.apple.com/library/ios/#DOCUMENTATION/Security/Reference/SecurityFrameworkReference/_index.html
The best approach I've seen is using the keychain. You can generate an UUID with the CFUUIDCreateString function and store it in the keychain. This data stays in the device between installs and restores from backups.
Use the devices Mac address. It's as unique as you could need I think.
How can I programmatically get the MAC address of an iphone

How to generate a good, non-changing UDID on an iPhone

In iOS 5 the usage of [[UIDevice currentDevice] uniqueIdentifier] got deprecated. We are now encouraged to use own-generated UUIDs and store them in the app's NSDefaults. That's OK for most usage, I guess.
But my question is - is it possible to generate somehow the UUID that would behave like the device ID right now - I would like to keep it the same even after the application is removed and reinstalled. The purpose of this is to help tracking possible fraud tries taken from the iPhone.
I'm wondering if usage of MAC-address, as with this category: https://github.com/erica/uidevice-extension/blob/master/UIDevice-Hardware.m would be OK?
The discussion for the uniqueIdentifier property in the documentation states:
Do not use the uniqueIdentifier property. To create a unique
identifier specific to your app, you can call the CFUUIDCreate
function to create a UUID, and write it to the defaults database using
the NSUserDefaults class.
Writing it to the user defaults should ensure that it is kept if the app is removed/reinstalled I would have thought.
Edit:
Sorry, they are not kept when an application is removed apparently. The documentation describes how to generate a UUID but I can't find out whether it is constant for a given user/device. I have seen some people proposing the use of keychain for persistence through app removal/re-installation but don't know how recommendable it is (and in any case the user can, I suppose, remove the entries).
Create your own UUID using the method described by Apple (the one pointed out by jbat), store it in NSUserDefaults.
Using iCloud you can then use the Key-value store to help 'persist' this UUID to a specific user, between installs and different devices.

Restrict voting on an iPhone app to a particular iPhone device

I am working on a client iPhone app which allows users to rate various services. There is no registration or login.
The requirement is that a user can not repeatedly rate a service(although can change their rating). As things currently stand the app could be deleted, re-installed and the user could vote again.
We considered using the device id, however a colleague mentioned that Apple recommend against this. If I understand correctly in case a phone was returned to store, re-issued, and the new user then downloaded the same app. Seems like a pretty edge case to me, but I guess could happen within an enterprise.
Is there a smart way to restrict voting to a particular device? Perhaps using the keychain?
Any pointers greatly appreciated.
Its important to note the difference between a UDID and a UUID.
UDID "unique device id" is hardware specific. It never changes for a particular device. For this reason, it has become a privacy concern and Apple is blocking apps that try to use this. As a result, Apple has generated an opt-out-able "device id" hash, particularly for advertisement usage. This new ID hash is called IFA and is available in iOS 6.0+.
UUID "universally unique id" is not hardware specific. It is a hash used to identify a device; but not particularly an absolute value. For example, PhoneGap generates a UUID based on device properties; this is what you get when you do device.uuid. If you delete the app and reinstall, you will get a new id hash. UUID is not being blocked by Apple.
I think the best solution in your case would be to use the IFA, with OpenUDID as a backup for iOS < 6.0.
Here is the code we use. If IFA is not available, get OpenUDID. You must install OpenUDID, read more about that here, https://github.com/ylechelle/OpenUDID.
NSString* uuid = nil;
if ([[UIDevice currentDevice] respondsToSelector:#selector(identifierForVendor)]) {
// IOS 6 new Unique Identifier implementation, IFA
uuid = [[[UIDevice currentDevice] identifierForVendor] UUIDString];
} else {
// Before iOS6 (or if IFA disabled) you shoud use a custom implementation for uuid
// Here I use OpenUDID (you have to import it into your project)
// https://github.com/ylechelle/OpenUDID
NSString* openUDID = [OpenUDID value];
uuid = [OpenUDID value];
}

Is it allowed to transfer iPhone UDID to my server?

My app has a feature which requires identifying each app users. I'm planning making the app sends UDID to my server. Server stores it, for later use.
I don't think that's a personal information, however, I want to know is it approvable or not in Apple's AppStore.
And, including transferring phone numbers. In the case of WhatsApp, it recognizes my friends' numbers automatically. I think that's impossible without some kind of data transfer.
You are allowed to transfer a device's UDID to your servers. That's what it's intended for.
Access to the UDID is grounds for rejection from the App Store. See an alternative to using the UDID at https://stackoverflow.com/a/10037636/1286639
Just make sure that it is no secret what your app does. If it transfers phone numbers to store those on your server then clearly mention this in the app's description or even ask the user for permission the first time.
That actually is a a reason to be rejected I think: not being clear about storing user's data on your own server/service.
Its important to note the difference between a UDID and a UUID.
UDID "unique device id" is hardware specific. It never changes for a particular device. For this reason, it has become a privacy concern and Apple is blocking apps that try to use this. As a result, Apple has generated an opt-out-able "device id" hash, particularly for advertisement usage. This new ID hash is called IFA and is available in iOS 6.0+.
UUID "universally unique id" is not hardware specific. It is a hash used to identify a device; but not particularly an absolute value. For example, PhoneGap generates a UUID based on device properties; this is what you get when you do device.uuid. If you delete the app and reinstall, you will get a new id hash. UUID is not being blocked by Apple.
I think the best solution in your case would be to use the IFA, with OpenUDID as a backup for iOS < 6.0.
Here is the code we use. If IFA is not available, get OpenUDID. [[You must install OpenUDID, read more about that here, https://github.com/ylechelle/OpenUDID.]]
NSString* uuid = nil;
if ([[UIDevice currentDevice] respondsToSelector:#selector(identifierForVendor)]) {
// IOS 6 new Unique Identifier implementation, IFA
uuid = [[[UIDevice currentDevice] identifierForVendor] UUIDString];
} else {
// Before iOS6 (or if IFA disabled) you shoud use a custom implementation for uuid
// Here I use OpenUDID (you have to import it into your project)
// https://github.com/ylechelle/OpenUDID
NSString* openUDID = [OpenUDID value];
uuid = [OpenUDID value];
}

Unique identifier for an iPhone app

For an iPhone app that submits images to a server I need somehow to tie all the images from a particular phone together. With every submit I'd like to send some unique phone id. Looked at
[[UIDevice mainDevice] uniqueIdentifier]
and
[[NSUserDefaults standardDefaults] stringForKey:#"SBFormattedPhoneNumber"]
but getting errors in the simulator.
Is there an Apple sanctioned way of doing this?
What errors are you getting? [[UIDevice currentDevice] uniqueIdentifier] (edited to fix API, thanks Martin!) is the officially recommended way of doing this.
You can also use CFUUID to generate a UUID. Here's some code:
NSString *uuid = nil;
CFUUIDRef theUUID = CFUUIDCreate(kCFAllocatorDefault);
if (theUUID) {
uuid = NSMakeCollectable(CFUUIDCreateString(kCFAllocatorDefault, theUUID));
[uuid autorelease];
CFRelease(theUUID);
}
By far the easiest and most appropriate way to obtain a unique identifier is to use the mechanisms Apple explicitly provides for obtaining one - [[UIDevice currentDevice] uniqueIdentifier]. You can not guarantee that the phone number will be unique to the device or that the device will even have a phone number. Beyond that, doing so is a horrible idea as it is a definite invasion of the user's privacy. Even the uniqueidentifier should be hashed if you are going to store it in any way.
In order to Persist the Unique Identifier you create between installations, you could use the Keychain Made easy with SSKeychain: Simply set your UUID as follows:
[SSKeychain setPassword:#"Your UUID" forService:#"com.yourapp.yourcompany" account:#"user"];
and then call it again anytime you need it:
NSString *retrieveuuid = [SSKeychain passwordForService:#"com.yourapp.yourcompany" account:#"user"];
Note: The services and accounts must match exactly.
Then, if the App is deleted and reinstalled, the UUID will persist with reinstallation.
If you then want to share this UUID across devices, set up your app to use iCloud. You can then store the UUID in NSUserDefaults, sync with KeyValueStore, and then set the UUID in the new devices keychain with the code above.
This answer would get extremely long if I typed code for all the above, but plenty of sample code around here to figure it all out.
Don't forget that in iOS 5 uniqueIdentifier will be deprecated you should use CFUUID instead of that
Interestingly, Apple has since deprecated the uniqueIdentifier in iOS 5 (as gN0Me mentioned). Here's the relevant TechCrunch article:
http://techcrunch.com/2011/08/19/apple-ios-5-phasing-out-udid/
Apple suggests that you no longer uniquely identify the device but instead identify the user. In most cases, this is excellent advice though there are some situations which still require a globally unique device ID. These scenarios are quite common in advertising. Hence, I wrote an extremely simple drop-in library which replicates the existing behavior exactly.
In a shameless plug of self promotion, I'll link it here in the hope that someone finds it useful. Also, I welcome all and any feedback/criticism:
http://www.binpress.com/app/myid/591
Nevertheless, in your particular situation I would advise skipping the globally unique ID functionality my library provides as it's a bit overkill for your situation. Instead, I would generate a simple CFUUID and store it in NSUserDefaults. This ID would be specific to your application but would allow you to group all the photos for that "app install" in your database.
In other words, by deprecating the uniqueIdentifier method, Apple is suggesting that you don't identify per device but instead per app install. Unless you are operating under specific conditions, chances are the per app ID fits your product better anyway.
This is an interesting problem that I am also looking into solving. Here is a scenario that I would like to address.
What happens when you sell your phone to another person... that Device ID will then belong to somebody else, so even if the app is removed from the iPhone, it could be re-added and all that data would then be re-associated to a new user... this is bad.
Using the Phone number with the Device ID MD5 would be a great solution. Another we came up with is having a SQL Lite DB with some token Hashed with the Device ID. Then when the app is removed the DB is killed and all the data is disassociated. I think that might be too brittle.
Any other ideas?
Rob Ellis (PhoneGap/Nitobi)
Use Apple's GenericKeyChain which is the best solution . Here is the working sample >>https://developer.apple.com/library/prerelease/ios/samplecode/GenericKeychain/Introduction/Intro.html
Have idea about KeyChainAccess >>https://developer.apple.com/library/mac/documentation/Security/Conceptual/keychainServConcepts/02concepts/concepts.html#//apple_ref/doc/uid/TP30000897-CH204-TP9
Haven't done iphone work, but how about taking a hash of something unique to the phone ... oh, say the phone number?
Getting iphone number
snippit:
NSString *phoneNumber = (NSString *) [[NSUserDefaults standardUserDefaults] objectForKey:#"SBFormattedPhoneNumber"]; // Will return null in simulator!
NSLog(#"Formatted phone number [%#]", phoneNumber);
I [recently] ran this code as-is on OS 2.2.1 [and OS 3.0].
It works as expected when run on the device, and returns my phone number with the full international dialing codes [ 1 in my case].
When run on the simulator, the value [returned] is a null string, so it only works on an actual iPhone device.
I did not test it on an iPod Touch.
...
Ran this code on a different device this week, and got a null value instead of the number.
On further research, it appears that the number returned by this code snippit is the number that is set up in iTunes for the device.
If you didn’t enter the iPhone’s number in iTunes at device activation, or perhaps (as in my case) if the default value wasn’t the iPhone’s number and you clicked OK anyway, such that iTunes doesn’t list the phone number when your iPhone is plugged in, this code will return a null string.
[Above is an edited concatenation of comments I recently posted to another article on this topic at http://www.alexcurylo.com/blog/2008/11/15/snippet-phone-number/]
Here is some more information on a way to get it from iTunes which may be useful for testing purposes.
I had success with such code:
- (NSString *)stringUniqueID {
NSString * result;
CFUUIDRef uuid;
CFStringRef uuidStr;
uuid = CFUUIDCreate(NULL);
assert(uuid != NULL);
uuidStr = CFUUIDCreateString(NULL, uuid);
assert(uuidStr != NULL);
result = [NSString stringWithFormat:#"%#", uuidStr];
assert(result != nil);
NSLog(#"UNIQUE ID %#", result);
CFRelease(uuidStr);
CFRelease(uuid);
return result;
}
You can use MAC address as a unique id. Following link will help you
How can I programmatically get the MAC address of an iphone